DocumentDB SQL - Funzioni definite dall'utente

DocumentDB SQL fornisce il supporto per le UDF (User-Defined Functions). Le UDF sono solo un altro tipo di funzioni JavaScript che puoi scrivere e funzionano praticamente come ti aspetteresti. È possibile creare UDF per estendere il linguaggio di query con logica aziendale personalizzata a cui è possibile fare riferimento nelle query.

La sintassi SQL di DocumentDB è stata estesa per supportare la logica dell'applicazione personalizzata utilizzando queste UDF. È possibile registrare le UDF con DocumentDB e quindi fare riferimento come parte di una query SQL.

Consideriamo i seguenti tre documenti per questo esempio.

AndersenFamily documento è il seguente.

{ 
   "id": "AndersenFamily", 
   "lastName": "Andersen", 
	
   "parents": [ 
      { "firstName": "Thomas", "relationship":  "father" }, 
      { "firstName": "Mary Kay", "relationship":  "mother" } 
   ],
   
   "children": [ 
      { 
         "firstName": "Henriette Thaulow", 
         "gender": "female", 
         "grade": 5, 
         "pets": [ { "givenName": "Fluffy", "type":  "Rabbit" } ] 
      } 
   ],
   
   "location": { "state": "WA", "county": "King", "city": "Seattle" }, 
   "isRegistered": true 
}

SmithFamily documento è il seguente.

{ 
   "id": "SmithFamily", 
	
   "parents": [ 
      { "familyName": "Smith", "givenName": "James" }, 
      { "familyName": "Curtis", "givenName": "Helen" }
   ], 
	
   "children": [ 
      { 
         "givenName": "Michelle", 
         "gender": "female", 
         "grade": 1 
      }, 
		
      { 
         "givenName": "John", 
         "gender": "male", 
         "grade": 7,
			
         "pets": [ 
            { "givenName": "Tweetie", "type": "Bird" } 
         ] 
      }
   ],
   
   "location": { 
      "state": "NY", 
      "county": "Queens", 
      "city": "Forest Hills" 
   },
   
   "isRegistered": true 
}

WakefieldFamily documento è il seguente.

{ 
   "id": "WakefieldFamily", 
	
   "parents": [ 
      { "familyName": "Wakefield", "givenName": "Robin" }, 
      { "familyName": "Miller", "givenName": "Ben" } 
   ],
   
   "children": [ 
      { 
         "familyName": "Merriam", 
         "givenName": "Jesse", 
         "gender": "female", 
         "grade": 6,
			
         "pets": [
            { "givenName": "Charlie Brown", "type": "Dog" }, 
            { "givenName": "Tiger", "type": "Cat" }, 
            { "givenName": "Princess", "type": "Cat" } 
         ] 
      },
		
      { 
         "familyName": "Miller", 
         "givenName": "Lisa", 
         "gender": "female", 
         "grade": 3,
			
         "pets": [ 
            { "givenName": "Jake", "type": "Snake" } 
         ] 
      } 
   ],
   
   "location": { "state": "NY", "county": "Manhattan", "city": "NY" }, 
   "isRegistered": false 
}

Diamo un'occhiata a un esempio in cui creeremo alcune semplici UDF.

Di seguito è riportata l'implementazione di CreateUserDefinedFunctions.

private async static Task CreateUserDefinedFunctions(DocumentClient client) { 
   Console.WriteLine(); 
   Console.WriteLine("**** Create User Defined Functions ****"); 
   Console.WriteLine();  
	
   await CreateUserDefinedFunction(client, "udfRegEx");  
}

Abbiamo un udfRegEx e in CreateUserDefinedFunction otteniamo il suo codice JavaScript dal nostro file locale. Costruiamo l'oggetto di definizione per la nuova UDF e chiamiamo CreateUserDefinedFunctionAsync con SelfLink della raccolta e l'oggetto udfDefinition come mostrato nel codice seguente.

private async static Task<UserDefinedFunction>
CreateUserDefinedFunction(DocumentClient client, string udfId) { 
   var udfBody = File.ReadAllText(@"..\..\Server\" + udfId + ".js"); 
	
   var udfDefinition = new UserDefinedFunction { 
      Id = udfId, 
      Body = udfBody 
   }; 
   
   var result = await client
      .CreateUserDefinedFunctionAsync(_collection.SelfLink, udfDefinition); 
   var udf = result.Resource; 
	
   Console.WriteLine("Created user defined function {0}; RID: {1}", 
      udf.Id, udf.ResourceId);  
		
   return udf; 
}

Recuperiamo la nuova UDF dalla proprietà della risorsa del risultato e la restituiamo al chiamante. Per visualizzare l'UDF esistente, di seguito è riportata l'implementazione diViewUserDefinedFunctions. Noi chiamiamoCreateUserDefinedFunctionQuery e scorrerli come al solito.

private static void ViewUserDefinedFunctions(DocumentClient client) { 
   Console.WriteLine(); 
   Console.WriteLine("**** View UDFs ****"); 
   Console.WriteLine(); 
	
   var udfs = client  
      .CreateUserDefinedFunctionQuery(_collection.UserDefinedFunctionsLink) 
      .ToList();  
		
   foreach (var udf in udfs) { 
      Console.WriteLine("User defined function {0}; RID: {1}", udf.Id, udf.ResourceId); 
   }
}

DocumentDB SQL non fornisce funzioni incorporate per la ricerca di sottostringhe o di espressioni regolari, quindi la seguente piccola riga riempie quella lacuna che è una funzione JavaScript.

function udfRegEx(input, regex) { 
   return input.match(regex); 
}

Data la stringa di input nel primo parametro, utilizzare il supporto di espressioni regolari integrato di JavaScript passando la stringa di corrispondenza del modello nel secondo parametro in.match. Possiamo eseguire una query di sottostringa per trovare tutti i negozi con la parola Andersen nel filelastName proprietà.

private static void Execute_udfRegEx(DocumentClient client) { 
   var sql = "SELECT c.name FROM c WHERE udf.udfRegEx(c.lastName, 'Andersen') != null";
	
   Console.WriteLine(); 
   Console.WriteLine("Querying for Andersen"); 
	
   var documents = client.CreateDocumentQuery(_collection.SelfLink, sql).ToList();  
   Console.WriteLine("Found {0} Andersen:", documents.Count); 
	
   foreach (var document in documents) { 
      Console.WriteLine("Id: {0}, Name: {1}", document.id, document.lastName); 
   } 
}

Notare che dobbiamo qualificare ogni riferimento UDF con il prefisso udf. Abbiamo appena passato l'SQL aCreateDocumentQuerycome una normale query. Infine, chiamiamo le query precedenti daCreateDocumentClient compito

private static async Task CreateDocumentClient() { 
   // Create a new instance of the DocumentClient 
	
   using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)){ 
      database = client.CreateDatabaseQuery("SELECT * FROM c WHERE 
         c.id = 'myfirstdb'").AsEnumerable().First();
      collection = client.CreateDocumentCollectionQuery(database.CollectionsLink, 
         "SELECT * FROM c WHERE c.id = 'Families'").AsEnumerable().First();
			 
      await CreateUserDefinedFunctions(client);
   
      ViewUserDefinedFunctions(client);
   
      Execute_udfRegEx(client); 
   } 
}

Quando il codice precedente viene eseguito, produce il seguente output.

**** Create User Defined Functions ****  
Created user defined function udfRegEx; RID: kV5oANVXnwAlAAAAAAAAYA==  
**** View UDFs ****  
User defined function udfRegEx; RID: kV5oANVXnwAlAAAAAAAAYA==  
Querying for Andersen 
Found 1 Andersen: 
 Id: AndersenFamily, Name: Andersen