One of the major features introduced in Couchbase Lite 2.0, is the new Query interface based on N1QL, Couchbase’s declarative query language that extends SQL for JSON. If you are familiar with SQL, you will feel right at home with the semantics of the new API. We covered the basics of the interface in an earlier postagem no blog. Arrays are an integral component of modeling data with JSON. In this blog post, we will discuss querying of array collections using the new API.
This blog assumes you are familiar with the fundamentals, so if you haven’t done so already, be sure to review the postagem anterior first. The last section of the post lists links to other relevant query blogs.
Histórico
Se você estava usando as versões 1.x do Couchbase Mobile, provavelmente está familiarizado com Visualizações de mapas para criar índices e consultas. Na versão 2.0, você não precisa mais criar visualizações e funções de mapa! Em vez disso, uma interface simples permite a criação de índices e você pode usar uma interface do Query Builder para construir suas consultas. A nova interface de consulta é mais simples de usar e muito mais poderosa em comparação. Vamos descobrir alguns de seus recursos nesta postagem.
Projeto de amostra
While the examples discussed here use Swift for iOS, note that barring some minor differences, the same query interface is supported on the Android and Windows platforms as well. So with some minor tweaks, you should be able to reuse the query examples in this post when working with other platforms.
Siga as instruções abaixo se você estiver interessado em um projeto Swift de amostra
- Clone o iOS Swift Playground do GitHub
1 |
$ git clone https://github.com/couchbaselabs/couchbase-lite-ios-api-playground |
- Siga as instruções de instalação no manual correspondente LEIAME para criar e executar o playground.
Modelo de dados de amostra
Usaremos o banco de dados Travel Sample localizado aqui
O conjunto de dados de amostra inclui vários tipos de documentos, conforme identificado pelo tipo
no documento. Vamos nos concentrar em documentos de tipo
"hotel" . The JSON document model is shown below. For brevity, we have omitted some of the properties from the model below.
Specifically, note that the model includes nested collections – public_likes
e revisões
. The queries in following sections will be dealing with these nested collections.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
{ "tipo": "hotel", "name" (nome): "Albergue da Juventude de Medway", "endereço": "Capstone Road, ME7 3JE", "cidade": "Medway", "país": "Reino Unido", "description" (descrição): "blah blah", "public_likes": [ "Julius Tromp I", "Corrine Hilll" ], "avaliações": [ { "autor": "Ozella Sipes", "content" (conteúdo): "blah blah.", "data": "2013–06–22 18:33:50 +0300", "ratings": { "Cleanliness": 5, "Localização": 4, "Overall": 4, "Rooms": 3, "Serviço": 5, "Value": 4 } }, { "autor": "Jeremy Snapes", "content" (conteúdo): "blah blah.", "data": "2013–05–05 18:33:50 +0300", "ratings": { "Cleanliness": 2, "Localização": 2, "Overall": 4, "Rooms": 3, "Serviço": 5, "Value": 4 } } ], "url":"http://www.yha.org.uk", "vaga": verdadeiro } |
** Consulte o modelo acima para cada um dos exemplos de consulta abaixo. **
O identificador do banco de dados
Nas consultas abaixo, usaremos o Banco de dados
API para abrir/criar o banco de dados CouchbaseLite.
1 2 |
var opções = DatabaseConfiguration() deixar db = tentar Banco de dados(nome: kDBName, configuração: opções) |
Índices
Para acelerar as consultas de leitura, você pode criar índices nas propriedades que serão consultadas. A melhoria no desempenho seria significativa em grandes conjuntos de dados. Obviamente, esteja ciente de que haverá um aumento na necessidade de armazenamento para guardar os índices, e o desempenho das gravações também poderá ser afetado. Portanto, tenha cuidado ao criar muitos índices.
O exemplo a seguir cria um Índice de valor
no tipo
propriedade de um documento
1 |
tentar db.createIndex(IndexBuilder.valueIndex(itens: ValueIndexItem.propriedade("tipo")),withName: "typeIndex") |
O exemplo a seguir cria um Índice de valor
em tipo
e nome
propriedades de um documento
1 |
tentar db.createIndex(IndexBuilder.valueIndex(itens: ValueIndexItem.propriedade("tipo"),ValueIndexItem.propriedade("name" (nome))),withName: "TypeNameIndex") |
Array Containment
The query below fetches the IDs, nomes e public_likes properties of documents where the public_likes
array property in "hotel" tipo
documents contains the value of “Corrine Hilll”. For this, the **ArrayFunction.contains**
function expression is used on the public_likes
array.
1 2 3 4 5 6 |
deixar pesquisa = QueryBuilde.selecionar(SelecionarResultado.expressão(Meta.id), SelecionarResultado.expressão(Expressão.propriedade("name" (nome))), SelecionarResultado.expressão(Expressão.propriedade("public_likes"))) .de(Fonte de dados.banco de dados(db)) .onde(Expressão.propriedade("tipo").igual a(Expressão.string("hotel")) .e( ArrayFunction.contém(Expressão.propriedade("public_likes"), valor: Expressão.string("Corrine Hilll")))) |
Array Size
The query below fetches the IDs, nomes properties and the tamanho de public_likes array property in "hotel" tipo
documents. For this, the **ArrayFunction.length**
function expression is used on the public_likes
array to get the size of the array.
Also, notice that we are using como
expression to alias the array count value to NumLikes. We had introduced aliases in the earlier blog post on Query Fundamentals. If you do not alias the result of the arrayLength
expression, the property key would be $1
, which is not very intuitive.
1 2 3 4 5 6 |
deixar pesquisa = Criador de consultas.selecionar(SelecionarResultado.expressão(Meta.id), SelecionarResultado.expressão(Expressão.propriedade("name" (nome))), SelecionarResultado.expressão(ArrayFunction.comprimento(Expressão.propriedade("public_likes"))).como("NumLikes")) .de(Fonte de dados.banco de dados(db)) .onde(Expressão.propriedade("tipo").igual a(Expressão.string("hotel"))) .limite(Expressão.int(limite)) |
Evaluating Array Members
Enquanto o ArrayFunction.contains
function expression allows you to check if the given array contains a specific value, the em
array expression can be used to evaluate any or all of the memebers of an array against a criteria specified by the satisfaz
expression. This is a powerful document filtering capability.
Oem
expression is used with the qualquer
, todos
ou o anyAndEvery
quantified operators on ArrayExpression
to evaluate any, every or any/every element in the array object.
The following query returns the documents where qualquer
of the values in the public_likes
array begins with the characters “Corr”.
1 2 3 4 5 6 7 8 9 10 11 |
//1. deixar VAR_LIKEDBY = ArrayExpression.variável("likedby") //2. deixar pesquisa = Criador de consultas.selecionar(SelecionarResultado.expressão(Meta.id), SelecionarResultado.expressão((Expressão.propriedade("public_likes")))) .de(Fonte de dados.banco de dados(db)) .onde(Expressão.propriedade("tipo").igual a(Expressão.string("hotel")) .e(ArrayExpression.qualquer(VAR_LIKEDBY).em(Expressão.propriedade("public_likes")) .satisfaz(VAR_LIKEDBY.como(Expressão.string("Cor%"))))) .limite(Expressão.int(limite))<código> |
-
- Declare a variable with name “likedby” to represent every element in the
public_likes
matriz - O
qualquer
ArrayExpression checks if the array element represented by thelikedby
variable satisfies the criteria in thecomo
expression. Thecomo
expression checks if the value of the item represented by the “likedby” variable begins with “Cor”.
- Declare a variable with name “likedby” to represent every element in the
Indexing Arrays
You can also query elements at specific indexes. The following query returns the nome
and first member of the public_likes
array properties of all “hotel” documents
1 2 3 4 5 6 |
deixar pesquisa = Criador de consultas.selecionar(SelecionarResultado.expressão(Meta.id), SelecionarResultado.expressão(Expressão.propriedade("name" (nome))), SelecionarResultado.expressão(Expressão.propriedade("public_likes[0]"))) .de(Fonte de dados.banco de dados(db)) .onde(Expressão.propriedade("tipo").igual a(Expressão.string("hotel"))) .limite(Expressão.int(limite)) |
Evaluating Nested Arrays
You can evaluate the members a nested array. For this, you can apply a keypath
to the variable expression. The nested array has to be one level deep.
The following query returns the documents where qualquer
of the values in the nested classificações
array has the Geral
property rating that is greater than or equal to 4.
As you may have noted from the data model above, the “reviews” property holds an array of objects. Each of the objects contain a nested classificações
array which in turn contains the Geral
propriedade.
1 2 3 4 5 6 7 8 9 10 11 12 |
// 1. deixar VAR_OVERALL = ArrayExpression.variável("review.ratings.Overall") //2. deixar VAR_REVIEWS = ArrayExpression.variável("revisão") //3. deixar pesquisa = Criador de consultas.selecionar(SelecionarResultado.expressão(Meta.id), SelecionarResultado.expressão(Expressão.propriedade("name" (nome)))) .de(Fonte de dados.banco de dados(db)) .onde(Expressão.propriedade("tipo").igual a(Expressão.string("hotel")) .e(ArrayExpression.qualquer(VAR_REVIEWS).em(Expressão.propriedade("avaliações")) .satisfaz(VAR_OVERALL.greaterThanOrEqualTo(Expressão.int(4))))) .limite(Expressão.int(limite)) |
- Declare a variable to represent an element in the
review.ratings.Overall
matriz - Declare a variable to represent every element in the
revisões
matriz - O
qualquer
expression checks if the array element represented by therevisão
variable satisfies the criteria in thecomparação
expression. Thecomparação
expression checks the value ofGeral
property of theclassificações
array in the object represented by the “review” variable is greater than or equal to 4.
Limitações
The array manipulation capabilities are not nearly as extensive as N1QL’s feature set. But it’s a good starting point. These capabilities may be available in future releases of Couchbase Mobile.
So for now, it’s upto the app to manipulate the array results using the language’s collection processing capabilities.
Let’s consider this example in swift
- Referring to the data model, let’s say you wanted to determine the mínimo
Limpeza
rating for a given hotel based on the reviews on the hotel.
From the model above , note that the Limpeza
property is a member of the the classificações
property contained in each object that is member of revisões
array.

For this, you can do a Couchbase Lite query to fetch the revisões
array property for a hotel with specified Id as follows –
1 2 3 4 5 6 |
// 1. Query for reviews property array for the given hotel deixar pesquisa = Criador de consultas.selecionar( SelecionarResultado.expressão(Expressão.propriedade("avaliações"))) .de(Fonte de dados.banco de dados(db)) .onde(Expressão.propriedade("tipo").igual a(Expressão.string("hotel")) .e(Meta.id.igual a(Expressão.string("hotel_10025")))) |
O resultSet
response to the above query would be an array with a single element. This element would correspond to the “hotel” document for the specified Id.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
[ { "avaliações": [ { "autor": "Ozella Sipes", "content" (conteúdo): "blah", "data": "2013–06–22 18:33:50 +0300", "ratings": { "Cleanliness": 5, "Localização": 4, "Overall": 4, "Rooms": 3, "Serviço": 5, "Value": 4 } }, { "autor": "fuzzy Snipes", "content" (conteúdo): "blah", "data": "2013–06–22 18:33:50 +0300", "ratings": { "Cleanliness": 2, "Localização": 3, "Overall": 4, "Rooms": 3, "Serviço": 5, "Value": 4 } } ] } ] |
Now, the app has to implement the logic to iterate over the revisões
array and for each member of the array, to fetch the classificações
property and corresponding Limpeza
valor.
Here is one possible way to do it in swift.
- First, iterate over the resultSet and extract the value of “reviews” property.
1 2 3 4 5 6 7 8 |
var jogos:[[Cordas:Qualquer]] = [[Cordas:Qualquer]]() fazer { para fila em tentar pesquisa.executar() { se deixar reviewData = fila.matriz(forKey: "avaliações")?.toArray() como? [[Cordas:Qualquer]] { jogos.anexar(reviewData) } } } |
After the loop processing, the “matches” array would be something like the one below. It would be an array containing the nested array corresponding to the reviews –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
[ [ { "autor": "Ozella Sipes", "content" (conteúdo): "blah", "data": "2013–06–22 18:33:50 +0300", "ratings": { "Cleanliness": 5, "Localização": 4, "Overall": 4, "Rooms": 3, "Serviço": 5, "Value": 4 } }, { "autor": "fuzzy Snipes", "content" (conteúdo): "blah", "data": "2013–06–22 18:33:50 +0300", "ratings": { "Cleanliness": 2, "Localização": 3, "Overall": 4, "Rooms": 3, "Serviço": 5, "Value": 4 } } ] ] |
- You can then use swift language features like
flatMap
emapa
to process the resulting array to derive the minimum “Cleanliness” rating for given hotel
1 2 3 4 5 6 |
deixar minCleanlinessValue = jogos.flatMap{$0} .mapa{retorno ($0["ratings"] como? [Cordas:Qualquer])?["Cleanliness"] como? Int} .flatMap{$0} .min { (a, b) -> Bool em retorno a < b } |
You would do something similar in languages that support functional constructs like mapa plano
e mapa
.
O que vem a seguir
This blog post looked at how you can handle Array collection types using the new Query API in Couchbase Mobile 2.0. This is a start. Expect to see more functionality in future releases. You can download the Pre-release build from our downloads página.
Aqui estão outras postagens relacionadas ao Couchbase Mobile Query que podem ser de interesse
- Isso postagem no blog discusses the fundamentals of the Query API
- Isso postagem no blog discute os recursos de pesquisa de texto completo.
- Isso postagem no blog discute como fazer consultas JOIN
Se tiver dúvidas ou comentários, deixe um comentário abaixo ou entre em contato comigo pelo Twitter @rajagp ou envie-me um e-mail priya.rajagopal@couchbase.com. O Fóruns do Couchbase são outro bom lugar para entrar em contato com perguntas.