DocumentDB SQL - Guia rápido
DocumentDB é a mais nova plataforma de banco de dados de documentos NoSQL da Microsoft que é executada no Azure. Neste tutorial, aprenderemos tudo sobre como consultar documentos usando a versão especial do SQL suportada pelo DocumentDB.
Banco de dados de documentos NoSQL
DocumentDB é o mais novo banco de dados de documentos NoSQL da Microsoft, no entanto, quando dizemos banco de dados de documentos NoSQL, o que exatamente queremos dizer com NoSQL e banco de dados de documentos?
SQL significa Structured Query Language que é uma linguagem de consulta tradicional de bancos de dados relacionais. SQL é freqüentemente equiparado a bancos de dados relacionais.
É realmente mais útil pensar em um banco de dados NoSQL como um banco de dados não relacional, então NoSQL realmente significa não relacional.
Existem diferentes tipos de bancos de dados NoSQL que incluem armazenamentos de valores-chave, como -
- Armazenamento de Tabela Azure
- Lojas baseadas em colunas, como Cassandra
- Bancos de dados gráficos, como NEO4
- Bancos de dados de documentos, como MongoDB e Azure DocumentDB
Por que Sintaxe SQL?
Isso pode parecer estranho à primeira vista, mas no DocumentDB, que é um banco de dados NoSQL, fazemos consultas usando SQL. Conforme mencionado acima, esta é uma versão especial do SQL com base na semântica JSON e JavaScript.
SQL é apenas uma linguagem, mas também é uma linguagem muito popular, rica e expressiva. Portanto, definitivamente parece uma boa ideia usar algum dialeto do SQL em vez de criar uma maneira totalmente nova de expressar consultas que precisaríamos aprender se você quisesse retirar documentos de seu banco de dados.
O SQL foi projetado para bancos de dados relacionais e o Banco de Dados de Documentos é um banco de dados de documentos não relacional. A equipe do DocumentDB, na verdade, adaptou a sintaxe SQL para o mundo não relacional dos bancos de dados de documentos, e isso é o que significa fazer o root de SQL em JSON e JavaScript.
A linguagem ainda é conhecida como SQL, mas a semântica é toda baseada em documentos JSON sem esquemas, em vez de tabelas relacionais. No Banco de Dados de Documentos, trabalharemos com tipos de dados JavaScript em vez de tipos de dados SQL. Estaremos familiarizados com SELECT, FROM, WHERE e assim por diante, mas com tipos de JavaScript, que são limitados a números e strings, objetos, arrays, Boolean e null são muito menos do que a ampla gama de tipos de dados SQL.
Da mesma forma, as expressões são avaliadas como expressões JavaScript em vez de alguma forma de T-SQL. Por exemplo, em um mundo de dados desnormalizados, não estamos lidando com as linhas e colunas, mas documentos sem esquema com estruturas hierárquicas que contêm matrizes e objetos aninhados.
Como funciona o SQL?
A equipe do DocumentDB respondeu a essa pergunta de várias maneiras inovadoras. Poucos deles estão listados a seguir -
Primeiro, supondo que você não mudou o comportamento padrão para indexar automaticamente todas as propriedades em um documento, você pode usar a notação pontilhada em suas consultas para navegar por um caminho para qualquer propriedade, não importa o quão profundamente aninhada ela possa estar dentro do documento.
Você também pode realizar uma junção intra-documento na qual elementos de matriz aninhados são juntados com seu elemento pai dentro de um documento de uma maneira muito semelhante à forma como uma junção é realizada entre duas tabelas no mundo relacional.
Suas consultas podem retornar documentos do banco de dados no estado em que se encontram, ou você pode projetar qualquer formato JSON personalizado que desejar com base nos dados do documento que desejar.
O SQL em DocumentDB suporta muitos dos operadores comuns, incluindo -
Operações aritméticas e bit a bit
Lógica AND e OR
Comparações de igualdade e alcance
Concatenação de string
A linguagem de consulta também oferece suporte a uma série de funções integradas.
O portal do Azure tem um Explorador de Consultas que nos permite executar qualquer consulta SQL em nosso banco de dados DocumentDB. Usaremos o Query Explorer para demonstrar os muitos recursos e recursos diferentes da linguagem de consulta, começando com a consulta mais simples possível.
Step 1 - Abra o Portal do Azure e, na folha do banco de dados, clique na folha Explorador de Consultas.
Lembre-se de que as consultas são executadas no escopo de uma coleção e, portanto, o Query Explorer nos permite escolher a coleção neste menu suspenso. Vamos deixá-lo definido para nossa coleção Famílias que contém os três documentos. Vamos considerar esses três documentos neste exemplo.
A seguir está o AndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
O Query Explorer é aberto com esta consulta simples SELECT * FROM c, que simplesmente recupera todos os documentos da coleção. Embora seja simples, ainda é bastante diferente da consulta equivalente em um banco de dados relacional.
Step 2- Em bancos de dados relacionais, SELECT * significa retornar todas as colunas enquanto estiver no Banco de Dados de Documentos. Isso significa que você deseja que cada documento do resultado seja retornado exatamente como está armazenado no banco de dados.
Mas quando você seleciona propriedades e expressões específicas em vez de simplesmente emitir um SELECT *, você está projetando uma nova forma que deseja para cada documento no resultado.
Step 3 - Clique em 'Executar' para executar a consulta e abrir a folha Resultados.
Como pode ser visto, WakefieldFamily, SmithFamily e AndersonFamily foram recuperados.
A seguir estão os três documentos que são recuperados como resultado do SELECT * FROM c inquerir.
[
{
"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,
"_rid": "Ic8LAJFujgECAAAAAAAAAA==",
"_ts": 1450541623,
"_self": "dbs/Ic8LAA==/colls/Ic8LAJFujgE=/docs/Ic8LAJFujgECAAAAAAAAAA==/",
"_etag": "\"00000500-0000-0000-0000-567582370000\"",
"_attachments": "attachments/"
},
{
"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,
"_rid": "Ic8LAJFujgEDAAAAAAAAAA==",
"_ts": 1450541623,
"_self": "dbs/Ic8LAA==/colls/Ic8LAJFujgE=/docs/Ic8LAJFujgEDAAAAAAAAAA==/",
"_etag": "\"00000600-0000-0000-0000-567582370000\"",
"_attachments": "attachments/"
},
{
"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,
"_rid": "Ic8LAJFujgEEAAAAAAAAAA==",
"_ts": 1450541624,
"_self": "dbs/Ic8LAA==/colls/Ic8LAJFujgE=/docs/Ic8LAJFujgEEAAAAAAAAAA==/",
"_etag": "\"00000700-0000-0000-0000-567582380000\"",
"_attachments": "attachments/"
}
]
No entanto, esses resultados também incluem as propriedades geradas pelo sistema que são todas prefixadas com o caractere de sublinhado.
Neste capítulo, abordaremos a cláusula FROM, que não funciona em nada como uma cláusula FROM padrão no SQL regular.
As consultas sempre são executadas no contexto de uma coleção específica e não podem ser unidas aos documentos da coleção, o que nos faz perguntar por que precisamos de uma cláusula FROM. Na verdade, não fazemos isso, mas se não o incluirmos, não estaremos consultando os documentos da coleção.
O objetivo desta cláusula é especificar a fonte de dados na qual a consulta deve operar. Normalmente, toda a coleção é a fonte, mas pode-se especificar um subconjunto da coleção. A cláusula FROM <from_specification> é opcional, a menos que a fonte seja filtrada ou projetada posteriormente na consulta.
Vamos dar uma olhada no mesmo exemplo novamente. A seguir está oAndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
Na consulta acima, “SELECT * FROM c”Indica que a coleção inteira de Famílias é a fonte sobre a qual enumerar.
Sub-documentos
A fonte também pode ser reduzida a um subconjunto menor. Quando queremos recuperar apenas uma subárvore em cada documento, a sub-raiz pode se tornar a fonte, conforme mostrado no exemplo a seguir.
Quando executamos a seguinte consulta -
SELECT * FROM Families.parents
Os seguintes subdocumentos serão recuperados.
[
[
{
"familyName": "Wakefield",
"givenName": "Robin"
},
{
"familyName": "Miller",
"givenName": "Ben"
}
],
[
{
"familyName": "Smith",
"givenName": "James"
},
{
"familyName": "Curtis",
"givenName": "Helen"
}
],
[
{
"firstName": "Thomas",
"relationship": "father"
},
{
"firstName": "Mary Kay",
"relationship": "mother"
}
]
]
Como resultado dessa consulta, podemos ver que apenas os subdocumentos pais são recuperados.
Neste capítulo, cobriremos a cláusula WHERE, que também é opcional como a cláusula FROM. Ele é usado para especificar uma condição ao buscar os dados na forma de documentos JSON fornecidos pela fonte. Qualquer documento JSON deve avaliar as condições especificadas como "verdadeiras" para ser considerado para o resultado. Se a condição fornecida for satisfeita, somente então ele retornará dados específicos na forma de documento (s) JSON. Podemos usar a cláusula WHERE para filtrar os registros e buscar apenas os registros necessários.
Vamos considerar os mesmos três documentos neste exemplo. A seguir está oAndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
Vamos dar uma olhada em um exemplo simples em que a cláusula WHERE é usada.
Nesta consulta, na cláusula WHERE, a condição (WHERE f.id = "WakefieldFamily") é especificada.
SELECT *
FROM f
WHERE f.id = "WakefieldFamily"
Quando a consulta acima for executada, ela retornará o documento JSON completo para WakefieldFamily, conforme mostrado na saída a seguir.
[
{
"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,
"_rid": "Ic8LAJFujgECAAAAAAAAAA==",
"_ts": 1450541623,
"_self": "dbs/Ic8LAA==/colls/Ic8LAJFujgE=/docs/Ic8LAJFujgECAAAAAAAAAA==/",
"_etag": "\"00000500-0000-0000-0000-567582370000\"",
"_attachments": "attachments/"
}
]
Um operador é uma palavra reservada ou um caractere usado principalmente em uma cláusula SQL WHERE para executar operação (ões), como comparações e operações aritméticas. O DocumentDB SQL também oferece suporte a uma variedade de expressões escalares. Os mais comumente usados sãobinary and unary expressions.
Os seguintes operadores SQL são atualmente suportados e podem ser usados em consultas.
Operadores de comparação SQL
A seguir está uma lista de todos os operadores de comparação disponíveis na gramática SQL do Banco de Dados de Documentos.
S.No. | Operadores e descrição |
---|---|
1 | = Verifica se os valores de dois operandos são iguais ou não. Se sim, a condição se torna verdadeira. |
2 | != Verifica se os valores de dois operandos são iguais ou não. Se os valores não forem iguais, a condição se torna verdadeira. |
3 | <> Verifica se os valores de dois operandos são iguais ou não. Se os valores não forem iguais, a condição se torna verdadeira. |
4 | > Verifica se o valor do operando esquerdo é maior que o valor do operando direito. Se sim, a condição se torna verdadeira. |
5 | < Verifica se o valor do operando esquerdo é menor que o valor do operando direito. Se sim, a condição se torna verdadeira. |
6 | >= Verifica se o valor do operando esquerdo é maior ou igual ao valor do operando direito. Se sim, a condição se torna verdadeira. |
7 | <= Verifica se o valor do operando esquerdo é menor ou igual ao valor do operando direito. Se sim, a condição se torna verdadeira. |
Operadores lógicos SQL
A seguir está uma lista de todos os operadores lógicos disponíveis na gramática SQL do Banco de Dados de Documentos.
S.No. | Operadores e descrição |
---|---|
1 | AND O operador AND permite a existência de várias condições na cláusula WHERE de uma instrução SQL. |
2 | BETWEEN O operador BETWEEN é usado para pesquisar valores que estão dentro de um conjunto de valores, dados o valor mínimo e o valor máximo. |
3 | IN O operador IN é usado para comparar um valor a uma lista de valores literais que foram especificados. |
4 | OR O operador OR é usado para combinar várias condições na cláusula WHERE de uma instrução SQL. |
5 | NOT O operador NOT inverte o significado do operador lógico com o qual é usado. Por exemplo, NOT EXISTS, NOT BETWEEN, NOT IN, etc. Este é um operador de negação. |
Operadores aritméticos SQL
A seguir está uma lista de todos os operadores aritméticos disponíveis na gramática SQL do DocumentDB.
S.No. | Operadores e descrição |
---|---|
1 | + Addition - Adiciona valores em qualquer lado do operador. |
2 | - Subtraction - Subtrai o operando direito do operando esquerdo. |
3 | * Multiplication - Multiplica valores em ambos os lados do operador. |
4 | / Division - Divide o operando à esquerda pelo operando à direita. |
5 | % Modulus - Divide o operando à esquerda pelo operando à direita e retorna o restante. |
Consideraremos os mesmos documentos também neste exemplo. A seguir está oAndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
Vamos dar uma olhada em um exemplo simples em que um operador de comparação é usado na cláusula WHERE.
Nesta consulta, na cláusula WHERE, a condição (WHERE f.id = "WakefieldFamily") é especificada e irá recuperar o documento cujo id é igual a WakefieldFamily.
SELECT *
FROM f
WHERE f.id = "WakefieldFamily"
Quando a consulta acima for executada, ela retornará o documento JSON completo para WakefieldFamily, conforme mostrado na saída a seguir.
[
{
"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,
"_rid": "Ic8LAJFujgECAAAAAAAAAA==",
"_ts": 1450541623,
"_self": "dbs/Ic8LAA==/colls/Ic8LAJFujgE=/docs/Ic8LAJFujgECAAAAAAAAAA==/",
"_etag": "\"00000500-0000-0000-0000-567582370000\"",
"_attachments": "attachments/"
}
]
Vamos dar uma olhada em outro exemplo em que a consulta recuperará os dados das crianças cuja nota é maior que 5.
SELECT *
FROM Families.children[0] c
WHERE (c.grade > 5)
Quando a consulta acima for executada, ela irá recuperar o seguinte sub-documento, conforme mostrado na saída.
[
{
"familyName": "Merriam",
"givenName": "Jesse",
"gender": "female",
"grade": 6,
"pets": [
{
"givenName": "Charlie Brown",
"type": "Dog"
},
{
"givenName": "Tiger",
"type": "Cat"
},
{
"givenName": "Princess",
"type": "Cat"
}
]
}
]
A palavra-chave BETWEEN é usada para expressar consultas em intervalos de valores como no SQL. BETWEEN pode ser usado contra strings ou números. A principal diferença entre usar BETWEEN no Banco de Dados de Documentos e ANSI SQL é que você pode expressar consultas de intervalo em propriedades de tipos mistos.
Por exemplo, em alguns documentos, é possível que você tenha "nota" como um número e em outros documentos podem ser strings. Nestes casos, uma comparação entre dois tipos diferentes de resultados é "indefinida" e o documento será ignorado.
Vamos considerar os três documentos do exemplo anterior. A seguir está oAndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
Vamos dar uma olhada em um exemplo, onde a consulta retorna todos os documentos da família em que a série do primeiro filho está entre 1-5 (ambos inclusivos).
A seguir está a consulta em que a palavra-chave BETWEEN é usada e o operador lógico AND.
SELECT *
FROM Families.children[0] c
WHERE c.grade BETWEEN 1 AND 5
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"givenName": "Michelle",
"gender": "female",
"grade": 1
},
{
"firstName": "Henriette Thaulow",
"gender": "female",
"grade": 5,
"pets": [
{
"givenName": "Fluffy",
"type": "Rabbit"
}
]
}
]
Para exibir as notas fora da faixa do exemplo anterior, use NOT BETWEEN conforme mostrado na consulta a seguir.
SELECT *
FROM Families.children[0] c
WHERE c.grade NOT BETWEEN 1 AND 5
Quando esta consulta é executada. Ele produz a seguinte saída.
[
{
"familyName": "Merriam",
"givenName": "Jesse",
"gender": "female",
"grade": 6,
"pets": [
{
"givenName": "Charlie Brown",
"type": "Dog"
},
{
"givenName": "Tiger",
"type": "Cat"
},
{
"givenName": "Princess",
"type": "Cat"
}
]
}
]
A palavra-chave IN pode ser usada para verificar se um valor especificado corresponde a qualquer valor em uma lista. O operador IN permite que você especifique vários valores em uma cláusula WHERE. IN é equivalente a encadear várias cláusulas OR.
Os três documentos semelhantes são considerados como feitos nos exemplos anteriores. A seguir está oAndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
Vamos dar uma olhada em um exemplo simples.
A seguir está a consulta que irá recuperar os dados cujo familyName seja “Smith” ou Wakefield.
SELECT *
FROM Families.parents[0] f
WHERE f.familyName IN ('Smith', 'Wakefield')
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"familyName": "Wakefield",
"givenName": "Robin"
},
{
"familyName": "Smith",
"givenName": "James"
}
]
Vamos considerar outro exemplo simples em que todos os documentos da família serão recuperados onde o id é "SmithFamily" ou "AndersenFamily". A seguir está a consulta.
SELECT *
FROM Families
WHERE Families.id IN ('SmithFamily', 'AndersenFamily')
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"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,
"_rid": "Ic8LAJFujgEDAAAAAAAAAA==",
"_ts": 1450541623,
"_self": "dbs/Ic8LAA==/colls/Ic8LAJFujgE=/docs/Ic8LAJFujgEDAAAAAAAAAA==/",
"_etag": "\"00000600-0000-0000-0000-567582370000\"",
"_attachments": "attachments/"
},
{
"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,
"_rid": "Ic8LAJFujgEEAAAAAAAAAA==",
"_ts": 1450541624,
"_self": "dbs/Ic8LAA==/colls/Ic8LAJFujgE=/docs/Ic8LAJFujgEEAAAAAAAAAA==/",
"_etag": "\"00000700-0000-0000-0000-567582380000\"",
"_attachments": "attachments/"
}
]
Quando você sabe que está retornando apenas um único valor, a palavra-chave VALUE pode ajudar a produzir um conjunto de resultados mais enxuto, evitando a sobrecarga de criar um objeto completo. A palavra-chave VALUE fornece uma maneira de retornar o valor JSON.
Vamos dar uma olhada em um exemplo simples.
A seguir está a consulta com a palavra-chave VALUE.
SELECT VALUE "Hello World, this is DocumentDB SQL Tutorial"
Quando esta consulta é executada, ela retorna o escalar "Hello World, este é o Tutorial do DocumentDB SQL".
[
"Hello World, this is DocumentDB SQL Tutorial"
]
Em outro exemplo, vamos considerar os três documentos dos exemplos anteriores.
A seguir está o AndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
A seguir está a consulta.
SELECT VALUE f.location
FROM Families f
Quando esta consulta é executada, ela retorna o endereço de retorno sem a etiqueta de localização.
[
{
"state": "NY",
"county": "Manhattan",
"city": "NY"
},
{
"state": "NY",
"county": "Queens",
"city": "Forest Hills"
},
{
"state": "WA",
"county": "King",
"city": "Seattle"
}
]
Se agora especificarmos a mesma consulta sem a palavra-chave VALUE, ela retornará o endereço com rótulo de local. A seguir está a consulta.
SELECT f.location
FROM Families f
Quando essa consulta é executada, ela produz a seguinte saída.
[
{
"location": {
"state": "NY",
"county": "Manhattan",
"city": "NY"
}
},
{
"location": {
"state": "NY",
"county": "Queens",
"city": "Forest Hills"
}
},
{
"location": {
"state": "WA",
"county": "King",
"city": "Seattle"
}
}
]
O Microsoft Azure DocumentDB oferece suporte à consulta de documentos usando SQL sobre documentos JSON. Você pode classificar os documentos da coleção em números e strings usando uma cláusula ORDER BY em sua consulta. A cláusula pode incluir um argumento ASC / DESC opcional para especificar a ordem em que os resultados devem ser recuperados.
Vamos considerar os mesmos documentos dos exemplos anteriores.
A seguir está o AndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
Vamos dar uma olhada em um exemplo simples.
A seguir está a consulta que contém a palavra-chave ORDER BY.
SELECT f.id, f.children[0].givenName,f.children[0].grade
FROM Families f
ORDER BY f.children[0].grade
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"id": "SmithFamily",
"givenName": "Michelle",
"grade": 1
},
{
"id": "AndersenFamily",
"grade": 5
},
{
"id": "WakefieldFamily",
"givenName": "Jesse",
"grade": 6
}
]
Vamos considerar outro exemplo simples.
A seguir está a consulta que contém a palavra-chave ORDER BY e a palavra-chave opcional DESC.
SELECT f.id, f.parents[0].familyName
FROM Families f
ORDER BY f.parents[0].familyName DESC
Quando a consulta acima for executada, ela produzirá a seguinte saída.
[
{
"id": "WakefieldFamily",
"familyName": "Wakefield"
},
{
"id": "SmithFamily",
"familyName": "Smith"
},
{
"id": "AndersenFamily"
}
]
No DocumentDB SQL, a Microsoft adicionou uma nova construção que pode ser usada com a palavra-chave IN para fornecer suporte para iteração em matrizes JSON. O suporte para iteração é fornecido na cláusula FROM.
Iremos considerar três documentos semelhantes dos exemplos anteriores novamente.
A seguir está o AndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
Vamos dar uma olhada em um exemplo simples sem a palavra-chave IN na cláusula FROM.
A seguir está a consulta que retornará todos os pais da coleção Famílias.
SELECT *
FROM Families.parents
Quando a consulta acima é executada, ela produz a seguinte saída.
[
[
{
"familyName": "Wakefield",
"givenName": "Robin"
},
{
"familyName": "Miller",
"givenName": "Ben"
}
],
[
{
"familyName": "Smith",
"givenName": "James"
},
{
"familyName": "Curtis",
"givenName": "Helen"
}
],
[
{
"firstName": "Thomas",
"relationship": "father"
},
{
"firstName": "Mary Kay",
"relationship": "mother"
}
]
]
Como pode ser visto na saída acima, os pais de cada família são exibidos em uma matriz JSON separada.
Vamos dar uma olhada no mesmo exemplo, porém desta vez usaremos a palavra-chave IN na cláusula FROM.
A seguir está a consulta que contém a palavra-chave IN.
SELECT *
FROM c IN Families.parents
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"familyName": "Wakefield",
"givenName": "Robin"
},
{
"familyName": "Miller",
"givenName": "Ben"
},
{
"familyName": "Smith",
"givenName": "James"
},
{
"familyName": "Curtis",
"givenName": "Helen"
},
{
"firstName": "Thomas",
"relationship": "father"
},
{
"firstName": "Mary Kay",
"relationship": "mother"
}
{
"id": "WakefieldFamily",
"givenName": "Jesse",
"grade": 6
}
]
No exemplo acima, pode-se ver que com iteração, a consulta que realiza iteração sobre os pais na coleção tem uma matriz de saída diferente. Portanto, todos os pais de cada família são adicionados em uma única matriz.
Em bancos de dados relacionais, a cláusula Joins é usada para combinar registros de duas ou mais tabelas em um banco de dados, e a necessidade de juntar as tabelas é muito importante ao projetar esquemas normalizados. Como o DocumentDB lida com o modelo de dados desnormalizado de documentos sem esquema, o JOIN no DocumentDB SQL é o equivalente lógico de um "selfjoin".
Vamos considerar os três documentos como nos exemplos anteriores.
A seguir está o AndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
Vamos dar uma olhada em um exemplo para entender como a cláusula JOIN funciona.
A seguir está a consulta que unirá o subdocumento root to children.
SELECT f.id
FROM Families f
JOIN c IN f.children
Quando a consulta acima for executada, ela produzirá a seguinte saída.
[
{
"id": "WakefieldFamily"
},
{
"id": "WakefieldFamily"
},
{
"id": "SmithFamily"
},
{
"id": "SmithFamily"
},
{
"id": "AndersenFamily"
}
]
No exemplo acima, a junção é entre a raiz do documento e a sub-raiz filha, o que cria um produto cruzado entre dois objetos JSON. A seguir estão alguns pontos a serem observados -
Na cláusula FROM, a cláusula JOIN é um iterador.
Os dois primeiros documentos WakefieldFamily e SmithFamily contêm dois filhos, portanto, o conjunto de resultados também contém o produto cruzado que produz um objeto separado para cada filho.
O terceiro documento AndersenFamily contém apenas um filho, portanto, há apenas um único objeto correspondente a este documento.
Vamos dar uma olhada no mesmo exemplo, mas desta vez recuperamos o nome do filho também para melhor compreensão da cláusula JOIN.
A seguir está a consulta que unirá o subdocumento root to children.
SELECT
f.id AS familyName,
c.givenName AS childGivenName,
c.firstName AS childFirstName
FROM Families f
JOIN c IN f.children
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"familyName": "WakefieldFamily",
"childGivenName": "Jesse"
},
{
"familyName": "WakefieldFamily",
"childGivenName": "Lisa"
},
{
"familyName": "SmithFamily",
"childGivenName": "Michelle"
},
{
"familyName": "SmithFamily",
"childGivenName": "John"
},
{
"familyName": "AndersenFamily",
"childFirstName": "Henriette Thaulow"
}
]
Em bancos de dados relacionais, aliases de SQL são usados para renomear temporariamente uma tabela ou cabeçalho de coluna. Da mesma forma, em DocumentDB, aliases são usados para renomear temporariamente um documento JSON, sub-documento, objeto ou qualquer campo.
A renomeação é uma mudança temporária e o documento real não muda. Basicamente, aliases são criados para tornar os nomes de campos / documentos mais legíveis. Para aliasing, a palavra-chave AS é usada, o que é opcional.
Vamos considerar três documentos semelhantes aos usados nos exemplos anteriores.
A seguir está o AndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
Vamos dar uma olhada em um exemplo para discutir os aliases.
A seguir está a consulta que unirá o subdocumento root to children. Temos aliases como f.id AS familyName, c.givenName AS childGivenName e c.firstName AS childFirstName.
SELECT
f.id AS familyName,
c.givenName AS childGivenName,
c.firstName AS childFirstName
FROM Families f
JOIN c IN f.children
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"familyName": "WakefieldFamily",
"childGivenName": "Jesse"
},
{
"familyName": "WakefieldFamily",
"childGivenName": "Lisa"
},
{
"familyName": "SmithFamily",
"childGivenName": "Michelle"
},
{
"familyName": "SmithFamily",
"childGivenName": "John"
},
{
"familyName": "AndersenFamily",
"childFirstName": "Henriette Thaulow"
}
]
A saída acima mostra que os nomes dos arquivos foram alterados, mas é uma alteração temporária e os documentos originais não foram modificados.
No DocumentDB SQL, a Microsoft adicionou um recurso-chave com a ajuda do qual podemos criar facilmente um array. Isso significa que quando executamos uma consulta, como resultado, ele criará uma matriz de coleção semelhante ao objeto JSON como resultado da consulta.
Vamos considerar os mesmos documentos dos exemplos anteriores.
A seguir está o AndersenFamily documento.
{
"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
}
A seguir está o SmithFamily documento.
{
"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
}
A seguir está o WakefieldFamily documento.
{
"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
}
Vamos dar uma olhada em um exemplo.
A seguir está a consulta que retornará o sobrenome e o endereço de cada família.
SELECT f.id AS FamilyName,
[f.location.city, f.location.county, f.location.state] AS Address
FROM Families f
Como pode ser visto, os campos de cidade, condado e estado estão entre colchetes, o que criará uma matriz e essa matriz é chamada de Endereço. Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"FamilyName": "WakefieldFamily",
"Address": [
"NY",
"Manhattan",
"NY"
]
},
{
"FamilyName": "SmithFamily",
"Address": [
"Forest Hills",
"Queens",
"NY"
]
},
{
"FamilyName": "AndersenFamily",
"Address": [
"Seattle",
"King",
"WA"
]
}
]
As informações de cidade, condado e estado são adicionadas à matriz Address na saída acima.
No DocumentDB SQL, a cláusula SELECT também oferece suporte a expressões escalares como constantes, expressões aritméticas, expressões lógicas, etc. Normalmente, as consultas escalares são raramente usadas, porque na verdade não consultam documentos na coleção, elas apenas avaliam expressões. Mas ainda é útil usar consultas de expressão escalar para aprender o básico, como usar expressões e moldar JSON em uma consulta, e esses conceitos se aplicam diretamente às consultas reais que você executará em documentos em uma coleção.
Vamos dar uma olhada em um exemplo que contém várias consultas escalares.
No Query Explorer, selecione apenas o texto a ser executado e clique em 'Executar'. Vamos ver este primeiro.
SELECT "Hello"
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"$1": "Hello"
}
]
Esta saída pode parecer um pouco confusa, então vamos analisá-la.
Primeiro, como vimos na última demonstração, os resultados da consulta estão sempre entre colchetes porque são retornados como uma matriz JSON, mesmo os resultados de consultas de expressão escalar como esta, que retorna apenas um único documento.
Temos uma matriz com um documento e esse documento possui uma única propriedade para a única expressão na instrução SELECT.
A instrução SELECT não fornece um nome para esta propriedade, portanto, DocumentDB gera um automaticamente usando $ 1.
Normalmente, não é isso que queremos, e é por isso que podemos usar AS para criar um alias para a expressão na consulta, o que define o nome da propriedade no documento gerado da maneira que você gostaria que fosse, palavra, neste exemplo.
SELECT "Hello" AS word
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"word": "Hello"
}
]
Da mesma forma, a seguir está outra consulta simples.
SELECT ((2 + 11 % 7)-2)/3
A consulta recupera a seguinte saída.
[
{
"$1": 1.3333333333333333
}
]
Vamos dar uma olhada em outro exemplo de modelagem de arrays aninhados e objetos incorporados.
SELECT
{
"words1":
["Hello", "World"],
"words2":
["How", "Are", "You?"]
} AS allWords
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"allWords": {
"words1": [
"Hello",
"World"
],
"words2": [
"How",
"Are",
"You?"
]
}
}
]
Em bancos de dados relacionais, uma consulta parametrizada é uma consulta na qual marcadores de posição são usados para parâmetros e os valores dos parâmetros são fornecidos em tempo de execução. O DocumentDB também oferece suporte a consultas parametrizadas, e os parâmetros em consultas parametrizadas podem ser expressos com a conhecida notação @. O motivo mais importante para usar consultas parametrizadas é evitar ataques de injeção de SQL. Ele também pode fornecer manipulação robusta e escape de entrada do usuário.
Vamos dar uma olhada em um exemplo em que usaremos o .Net SDK. A seguir está o código que excluirá a coleção.
private async static Task DeleteCollection(DocumentClient client, string collectionId) {
Console.WriteLine();
Console.WriteLine(">>> Delete Collection {0} in {1} <<<",
collectionId, _database.Id);
var query = new SqlQuerySpec {
QueryText = "SELECT * FROM c WHERE c.id = @id",
Parameters = new SqlParameterCollection { new SqlParameter { Name =
"@id", Value = collectionId } }
};
DocumentCollection collection = client.CreateDocumentCollectionQuery(database.SelfLink,
query).AsEnumerable().First();
await client.DeleteDocumentCollectionAsync(collection.SelfLink);
Console.WriteLine("Deleted collection {0} from database {1}",
collectionId, _database.Id);
}
A construção de uma consulta parametrizada é a seguinte.
var query = new SqlQuerySpec {
QueryText = "SELECT * FROM c WHERE c.id = @id",
Parameters = new SqlParameterCollection { new SqlParameter { Name =
"@id", Value = collectionId } }
};
Não estamos codificando o collectionId, portanto, este método pode ser usado para excluir qualquer coleção. Podemos usar o símbolo '@' para prefixar nomes de parâmetros, semelhante ao SQL Server.
No exemplo acima, estamos consultando por uma coleção específica por Id, onde o parâmetro Id é definido neste SqlParameterCollection atribuído à propriedade do parâmetro deste SqlQuerySpec. O SDK então faz o trabalho de construir a string de consulta final para o DocumentDB com o collectionId embutido nele. Executamos a consulta e, em seguida, usamos seu SelfLink para excluir a coleção.
A seguir está a implementação da tarefa CreateDocumentClient.
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 = 'earthquake'").AsEnumerable().First();
collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
"SELECT * FROM c WHERE c.id = 'myfirstdb'").AsEnumerable().First();
await DeleteCollection(client, "MyCollection1");
await DeleteCollection(client, "MyCollection2");
}
}
Quando o código é executado, ele produz a seguinte saída.
**** Delete Collection MyCollection1 in mydb ****
Deleted collection MyCollection1 from database myfirstdb
**** Delete Collection MyCollection2 in mydb ****
Deleted collection MyCollection2 from database myfirstdb
Vamos dar uma olhada em outro exemplo. Podemos escrever uma consulta que recebe o sobrenome e o estado do endereço como parâmetros e, em seguida, executa-a para vários valores de sobrenome e localização.estado com base na entrada do usuário.
SELECT *
FROM Families f
WHERE f.lastName = @lastName AND f.location.state = @addressState
Essa solicitação pode então ser enviada ao DocumentDB como uma consulta JSON parametrizada, conforme mostrado no código a seguir.
{
"query": "SELECT * FROM Families f WHERE f.lastName = @lastName AND
f.location.state = @addressState",
"parameters": [
{"name": "@lastName", "value": "Wakefield"},
{"name": "@addressState", "value": "NY"},
]
}
O DocumentDB oferece suporte a um host de funções integradas para operações comuns que podem ser usadas dentro de consultas. Há um monte de funções para realizar cálculos matemáticos e também funções de verificação de tipo que são extremamente úteis ao trabalhar com esquemas variados. Essas funções podem testar se uma determinada propriedade existe e se existe se é um número ou uma string, booleano ou objeto.
Também obtemos essas funções úteis para analisar e manipular strings, bem como várias funções para trabalhar com arrays, permitindo fazer coisas como concatenar arrays e testar para ver se um array contém um elemento específico.
A seguir estão os diferentes tipos de funções integradas -
S.No. | Funções integradas e descrição |
---|---|
1 | Funções Matemáticas As funções matemáticas executam um cálculo, geralmente com base em valores de entrada fornecidos como argumentos, e retornam um valor numérico. |
2 | Funções de verificação de tipo As funções de verificação de tipo permitem verificar o tipo de uma expressão nas consultas SQL. |
3 | Funções de String As funções de string executam uma operação em um valor de entrada de string e retornam um valor string, numérico ou booleano. |
4 | Funções de matriz As funções de array executam uma operação em um valor de entrada de array e retornam na forma de valor numérico, booleano ou array. |
5 | Funções Espaciais O DocumentDB também oferece suporte às funções integradas do Open Geospatial Consortium (OGC) para consultas geoespaciais. |
No DocumentDB, na verdade usamos SQL para consultar documentos. Se estivermos fazendo desenvolvimento .NET, também haverá um provedor LINQ que pode ser usado e que pode gerar SQL apropriado a partir de uma consulta LINQ.
Tipos de dados suportados
No DocumentDB, todos os tipos primitivos JSON são suportados no provedor LINQ incluído no DocumentDB .NET SDK, que são os seguintes -
- Numeric
- Boolean
- String
- Null
Expressão Suportada
As seguintes expressões escalares são suportadas no provedor LINQ incluído no DocumentDB .NET SDK.
Constant Values - Inclui valores constantes dos tipos de dados primitivos.
Property/Array Index Expressions - As expressões referem-se à propriedade de um objeto ou elemento de matriz.
Arithmetic Expressions - Inclui expressões aritméticas comuns em valores numéricos e booleanos.
String Comparison Expression - Inclui a comparação de um valor de string com algum valor de string constante.
Object/Array Creation Expression- Retorna um objeto do tipo de valor composto ou tipo anônimo ou uma matriz de tais objetos. Esses valores podem ser aninhados.
Operadores LINQ com suporte
Aqui está uma lista de operadores LINQ com suporte no provedor LINQ incluído no DocumentDB .NET SDK.
Select - As projeções são convertidas em SQL SELECT, incluindo a construção de objetos.
Where- Os filtros traduzem para o SQL WHERE e oferecem suporte à tradução entre &&, || e! para os operadores SQL.
SelectMany- Permite o desenrolar de matrizes para a cláusula SQL JOIN. Pode ser usado para encadear / aninhar expressões para filtrar elementos da matriz.
OrderBy and OrderByDescending - Traduz-se em ORDER BY ascendente / descendente.
CompareTo- Traduz em comparações de intervalo. Normalmente usado para strings, uma vez que não são comparáveis no .NET.
Take - Traduz para o SQL TOP para limitar os resultados de uma consulta.
Math Functions - Suporta tradução de Abs, Acos, Asin, Atan, Ceiling, Cos, Exp, Floor, Log, Log10, Pow, Round, Sign, Sin, Sqrt, Tan, Truncate para as funções integradas SQL equivalentes.
String Functions - Suporta tradução de Concat, Contains, EndsWith, IndexOf, Count, ToLower, TrimStart, Replace, Reverse, TrimEnd, StartsWith, SubString, ToUpper do .NET para as funções integradas SQL equivalentes.
Array Functions - Suporta tradução de Concat, Contains e Count do .NET para as funções integradas SQL equivalentes.
Geospatial Extension Functions - Suporta conversão de métodos stub Distance, Within, IsValid e IsValidDetailed para as funções integradas SQL equivalentes.
User-Defined Extension Function - Suporta tradução do método stub UserDefinedFunctionProvider.Invoke para a função definida pelo usuário correspondente.
Miscellaneous- Suporta tradução de operadores condicionais e de coalescência. Pode traduzir Contains para String CONTAINS, ARRAY_CONTAINS ou SQL IN dependendo do contexto.
Vamos dar uma olhada em um exemplo em que usaremos o .Net SDK. A seguir estão os três documentos que consideraremos para este exemplo.
Novo Cliente 1
{
"name": "New Customer 1",
"address": {
"addressType": "Main Office",
"addressLine1": "123 Main Street",
"location": {
"city": "Brooklyn",
"stateProvinceName": "New York"
},
"postalCode": "11229",
"countryRegionName": "United States"
},
}
Novo Cliente 2
{
"name": "New Customer 2",
"address": {
"addressType": "Main Office",
"addressLine1": "678 Main Street",
"location": {
"city": "London",
"stateProvinceName": " London "
},
"postalCode": "11229",
"countryRegionName": "United Kingdom"
},
}
Novo Cliente 3
{
"name": "New Customer 3",
"address": {
"addressType": "Main Office",
"addressLine1": "12 Main Street",
"location": {
"city": "Brooklyn",
"stateProvinceName": "New York"
},
"postalCode": "11229",
"countryRegionName": "United States"
},
}
A seguir está o código em que consultamos usando LINQ. Definimos uma consulta LINQ emq, mas não será executado até executarmos .ToList nele.
private static void QueryDocumentsWithLinq(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Query Documents (LINQ) ****");
Console.WriteLine();
Console.WriteLine("Quering for US customers (LINQ)");
var q =
from d in client.CreateDocumentQuery<Customer>(collection.DocumentsLink)
where d.Address.CountryRegionName == "United States"
select new {
Id = d.Id,
Name = d.Name,
City = d.Address.Location.City
};
var documents = q.ToList();
Console.WriteLine("Found {0} US customers", documents.Count);
foreach (var document in documents) {
var d = document as dynamic;
Console.WriteLine(" Id: {0}; Name: {1}; City: {2}", d.Id, d.Name, d.City);
}
Console.WriteLine();
}
O SDK converterá nossa consulta LINQ em sintaxe SQL para DocumentDB, gerando uma cláusula SELECT e WHERE com base em nossa sintaxe LINQ.
Vamos chamar as consultas acima da tarefa CreateDocumentClient.
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 = 'MyCollection'").AsEnumerable().First();
QueryDocumentsWithLinq(client);
}
}
Quando o código acima é executado, ele produz a seguinte saída.
**** Query Documents (LINQ) ****
Quering for US customers (LINQ)
Found 2 US customers
Id: 7e9ad4fa-c432-4d1a-b120-58fd7113609f; Name: New Customer 1; City: Brooklyn
Id: 34e9873a-94c8-4720-9146-d63fb7840fad; Name: New Customer 1; City: Brooklyn
Atualmente, o JavaScript está em todo lugar, não apenas nos navegadores. O DocumentDB adota o JavaScript como uma espécie de T-SQL moderno e suporta a execução transacional da lógica do JavaScript nativamente, dentro do mecanismo de banco de dados. O DocumentDB fornece um modelo de programação para executar a lógica do aplicativo baseado em JavaScript diretamente nas coleções em termos de procedimentos armazenados e gatilhos.
Vamos dar uma olhada em um exemplo em que criamos um procedimento de armazenamento simples. A seguir estão as etapas -
Step 1 - Crie um novo aplicativo de console.
Step 2- Adicione o .NET SDK do NuGet. Estamos usando o .NET SDK aqui, o que significa que escreveremos algum código C # para criar, executar e, em seguida, excluir nosso procedimento armazenado, mas o próprio procedimento armazenado é escrito em JavaScript.
Step 3 - Clique com o botão direito do mouse no projeto no Solution explorer.
Step 4 - Adicione um novo arquivo JavaScript para o procedimento armazenado e chame-o de HelloWorldStoreProce.js
Cada procedimento armazenado é apenas uma função JavaScript, então criaremos uma nova função e, naturalmente, também nomearemos esta função HelloWorldStoreProce. Não importa se dermos um nome à função. O Banco de Dados de Documentos só fará referência a este procedimento armazenado pelo Id que fornecemos ao criá-lo.
function HelloWorldStoreProce() {
var context = getContext();
var response = context.getResponse();
response.setBody('Hello, and welcome to DocumentDB!');
}
Tudo o que o procedimento armazenado faz é obter o objeto de resposta do contexto e chamar seu setBodymétodo para retornar uma string para o chamador. No código C #, vamos criar o procedimento armazenado, executá-lo e, em seguida, excluí-lo.
Os procedimentos armazenados têm o escopo definido por coleção, portanto, precisaremos do SelfLink da coleção para criar o procedimento armazenado.
Step 5 - Primeira consulta para o myfirstdb banco de dados e então para o MyCollection coleção.
Criar um procedimento armazenado é como criar qualquer outro recurso no Banco de Dados de Documentos.
private async static Task SimpleStoredProcDemo() {
var endpoint = "https://azuredocdbdemo.documents.azure.com:443/";
var masterKey =
"BBhjI0gxdVPdDbS4diTjdloJq7Fp4L5RO/StTt6UtEufDM78qM2CtBZWbyVwFPSJIm8AcfDu2O+AfV T+TYUnBQ==";
using (var client = new DocumentClient(new Uri(endpoint), masterKey)) {
// Get database
Database database = client
.CreateDatabaseQuery("SELECT * FROM c WHERE c.id = 'myfirstdb'")
.AsEnumerable()
.First();
// Get collection
DocumentCollection collection = client
.CreateDocumentCollectionQuery(database.CollectionsLink, "SELECT * FROM
c WHERE c.id = 'MyCollection'")
.AsEnumerable()
.First();
// Create stored procedure
var sprocBody = File.ReadAllText(@"..\..\HelloWorldStoreProce.js");
var sprocDefinition = new StoredProcedure {
Id = "HelloWorldStoreProce",
Body = sprocBody
};
StoredProcedure sproc = await client.
CreateStoredProcedureAsync(collection.SelfLink, sprocDefinition);
Console.WriteLine("Created stored procedure {0} ({1})",
sproc.Id, sproc.ResourceId);
// Execute stored procedure
var result = await client.ExecuteStoredProcedureAsync
(sproc.SelfLink); Console.WriteLine("Executed stored procedure; response = {0}", result.Response); // Delete stored procedure await client.DeleteStoredProcedureAsync(sproc.SelfLink); Console.WriteLine("Deleted stored procedure {0} ({1})", sproc.Id, sproc.ResourceId); } }
Step 6 - Primeiro crie um objeto de definição com o Id para o novo recurso e, em seguida, chame um dos métodos Create no DocumentClientobjeto. No caso de um procedimento armazenado, a definição inclui o Id e o código JavaScript real que você deseja enviar para o servidor.
Step 7 - Ligue File.ReadAllText para extrair o código do procedimento armazenado do arquivo JS.
Step 8 - Atribua o código de procedimento armazenado à propriedade body do objeto de definição.
No que diz respeito ao Banco de Dados de Documentos, o Id que especificamos aqui, na definição, é o nome do procedimento armazenado, independentemente de como realmente nomeamos a função JavaScript.
No entanto, ao criar procedimentos armazenados e outros objetos do lado do servidor, é recomendável nomear as funções JavaScript e que esses nomes de função correspondam ao Id que definimos para DocumentDB.
Step 9 - Ligue CreateStoredProcedureAsync, passando no SelfLink para o MyCollectioncoleção e a definição do procedimento armazenado. Isso cria o procedimento armazenado eResourceId que o Banco de Dados de Documentos atribuído a ele.
Step 10 - Chame o procedimento armazenado. ExecuteStoredProcedureAsyncusa um parâmetro de tipo que você define para o tipo de dados esperado do valor retornado pelo procedimento armazenado, que você pode especificar simplesmente como um objeto se quiser um objeto dinâmico retornado. Esse é um objeto cujas propriedades serão vinculadas em tempo de execução.
Neste exemplo, sabemos que nosso procedimento armazenado está apenas retornando uma string e então chamamos ExecuteStoredProcedureAsync<string>.
A seguir está a implementação completa do arquivo Program.cs.
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DocumentDBStoreProce {
class Program {
private static void Main(string[] args) {
Task.Run(async () => {
await SimpleStoredProcDemo();
}).Wait();
}
private async static Task SimpleStoredProcDemo() {
var endpoint = "https://azuredocdbdemo.documents.azure.com:443/";
var masterKey =
"BBhjI0gxdVPdDbS4diTjdloJq7Fp4L5RO/StTt6UtEufDM78qM2CtBZWbyVwFPSJIm8AcfDu2O+AfV T+TYUnBQ==";
using (var client = new DocumentClient(new Uri(endpoint), masterKey)) {
// Get database
Database database = client
.CreateDatabaseQuery("SELECT * FROM c WHERE c.id = 'myfirstdb'")
.AsEnumerable()
.First();
// Get collection
DocumentCollection collection = client
.CreateDocumentCollectionQuery(database.CollectionsLink,
"SELECT * FROM c WHERE c.id = 'MyCollection'")
.AsEnumerable()
.First();
// Create stored procedure
var sprocBody = File.ReadAllText(@"..\..\HelloWorldStoreProce.js");
var sprocDefinition = new StoredProcedure {
Id = "HelloWorldStoreProce",
Body = sprocBody
};
StoredProcedure sproc = await client
.CreateStoredProcedureAsync(collection.SelfLink, sprocDefinition);
Console.WriteLine("Created stored procedure {0} ({1})", sproc
.Id, sproc.ResourceId);
// Execute stored procedure
var result = await client
.ExecuteStoredProcedureAsync<string>(sproc.SelfLink);
Console.WriteLine("Executed stored procedure; response = {0}",
result.Response);
// Delete stored procedure
await client.DeleteStoredProcedureAsync(sproc.SelfLink);
Console.WriteLine("Deleted stored procedure {0} ({1})",
sproc.Id, sproc.ResourceId);
}
}
}
}
Quando o código acima é executado, ele produz a seguinte saída.
Created stored procedure HelloWorldStoreProce (Ic8LAMEUVgACAAAAAAAAgA==)
Executed stored procedure; response = Hello, and welcome to DocumentDB!
Como visto na saída acima, a propriedade de resposta tem o "Olá e bem-vindo ao Banco de Dados de Documentos!" retornado por nosso procedimento armazenado.
O DocumentDB SQL fornece suporte para funções definidas pelo usuário (UDFs). UDFs são apenas outro tipo de funções JavaScript que você pode escrever e funcionam exatamente como você espera. Você pode criar UDFs para estender a linguagem de consulta com lógica de negócios personalizada que pode ser referenciada em suas consultas.
A sintaxe do DocumentDB SQL é estendida para oferecer suporte à lógica de aplicativo personalizado usando esses UDFs. UDFs podem ser registrados no Banco de Dados de Documentos e, em seguida, referenciados como parte de uma consulta SQL.
Vamos considerar os três documentos a seguir para este exemplo.
AndersenFamily documento é o seguinte.
{
"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 é o seguinte.
{
"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 é o seguinte.
{
"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
}
Vamos dar uma olhada em um exemplo em que criaremos alguns UDFs simples.
A seguir está a implementação de CreateUserDefinedFunctions.
private async static Task CreateUserDefinedFunctions(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Create User Defined Functions ****");
Console.WriteLine();
await CreateUserDefinedFunction(client, "udfRegEx");
}
Temos um udfRegEx, e em CreateUserDefinedFunction obtemos seu código JavaScript de nosso arquivo local. Construímos o objeto de definição para o novo UDF e chamamos CreateUserDefinedFunctionAsync com o SelfLink da coleção e o objeto udfDefinition conforme mostrado no código a seguir.
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;
}
Recebemos o novo UDF da propriedade de recurso do resultado e o devolvemos ao chamador. Para exibir o UDF existente, a seguir está a implementação deViewUserDefinedFunctions. Nós chamamosCreateUserDefinedFunctionQuery e percorrê-los como de costume.
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);
}
}
O DocumentDB SQL não fornece funções integradas para pesquisar substrings ou expressões regulares, portanto, a pequena linha a seguir preenche essa lacuna que é uma função JavaScript.
function udfRegEx(input, regex) {
return input.match(regex);
}
Dada a string de entrada no primeiro parâmetro, use o suporte integrado de expressão regular do JavaScript, passando a string de correspondência de padrão no segundo parâmetro para.match. Podemos executar uma consulta de substring para encontrar todas as lojas com a palavra Andersen em seuslastName propriedade.
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);
}
}
Observe que devemos qualificar cada referência UDF com o prefixo udf. Acabamos de passar o SQL paraCreateDocumentQuerycomo qualquer consulta comum. Finalmente, vamos chamar as consultas acima doCreateDocumentClient tarefa
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 o código acima é executado, ele produz a seguinte saída.
**** 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
Composite Querypermite combinar dados de consultas existentes e, em seguida, aplicar filtros, agregações e assim por diante antes de apresentar os resultados do relatório, que mostram o conjunto de dados combinado. A Consulta composta recupera vários níveis de informações relacionadas em consultas existentes e apresenta os dados combinados como um resultado de consulta único e nivelado.
Usando a consulta composta, você também tem a opção de -
Selecione a opção de remoção de SQL para remover tabelas e campos que não são necessários com base nas seleções de atributos dos usuários.
Defina as cláusulas ORDER BY e GROUP BY.
Defina a cláusula WHERE como um filtro sobre o conjunto de resultados de uma consulta composta.
Os operadores acima podem ser compostos para formar consultas mais poderosas. Como o DocumentDB oferece suporte a coleções aninhadas, a composição pode ser concatenada ou aninhada.
Vamos considerar os seguintes documentos para este exemplo.
AndersenFamily documento é o seguinte.
{
"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 é o seguinte.
{
"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 é o seguinte.
{
"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
}
Vamos dar uma olhada em um exemplo de consulta concatenada.
A seguir está a consulta que irá recuperar o id e a localização da família onde o primeiro filho givenName é Michelle.
SELECT f.id,f.location
FROM Families f
WHERE f.children[0].givenName = "Michelle"
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"id": "SmithFamily",
"location": {
"state": "NY",
"county": "Queens",
"city": "Forest Hills"
}
}
]
Vamos considerar outro exemplo de consulta concatenada.
Segue a consulta que retornará todos os documentos cujo primeiro filho tenha nota maior que 3.
SELECT *
FROM Families f
WHERE ({grade: f.children[0].grade}.grade > 3)
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"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,
"_rid": "Ic8LAJFujgECAAAAAAAAAA==",
"_ts": 1450541623,
"_self": "dbs/Ic8LAA==/colls/Ic8LAJFujgE=/docs/Ic8LAJFujgECAAAAAAAAAA==/",
"_etag": "\"00000500-0000-0000-0000-567582370000\"",
"_attachments": "attachments/"
},
{
"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,
"_rid": "Ic8LAJFujgEEAAAAAAAAAA==",
"_ts": 1450541624,
"_self": "dbs/Ic8LAA==/colls/Ic8LAJFujgE=/docs/Ic8LAJFujgEEAAAAAAAAAA==/",
"_etag": "\"00000700-0000-0000-0000-567582380000\"",
"_attachments": "attachments/"
}
]
Vamos dar uma olhada em um example de consultas aninhadas.
A seguir está a consulta que irá iterar todos os pais e, em seguida, retornar o documento onde familyName é Smith.
SELECT *
FROM p IN Families.parents
WHERE p.familyName = "Smith"
Quando a consulta acima é executada, ela produz a seguinte saída.
[
{
"familyName": "Smith",
"givenName": "James"
}
]
Vamos considerar another example de consulta aninhada.
A seguir está a consulta que retornará todos os familyName.
SELECT VALUE p.familyName
FROM Families f
JOIN p IN f.parents
Quando a consulta acima é executada, ela produz a seguinte saída.
[
"Wakefield",
"Miller",
"Smith",
"Curtis"
]