Consultar Arrays no MongoDB

MongoDBBeginner
Pratique Agora

Introdução

Neste laboratório, você aprenderá como consultar arrays de forma eficaz no MongoDB. Arrays são uma estrutura de dados fundamental no MongoDB, permitindo que você armazene listas de valores em um único campo de documento. Este laboratório irá guiá-lo através das técnicas essenciais para trabalhar com dados de array, desde a correspondência simples de elementos até consultas mais complexas usando operadores especializados. Você aprenderá a encontrar documentos com base no conteúdo do array, tamanho e posição do elemento, que são habilidades cruciais para qualquer desenvolvedor que trabalhe com MongoDB.

Introdução e Correspondência Básica de Arrays

Nesta primeira etapa, você se conectará ao servidor MongoDB, criará um banco de dados e inserirá alguns dados de exemplo. Em seguida, você realizará consultas básicas para encontrar documentos correspondendo a elementos dentro de um array.

Primeiro, abra o MongoDB Shell (mongosh) para interagir com seu banco de dados. Este comando o conectará à instância MongoDB em execução.

mongosh

Uma vez dentro do shell, você verá um prompt test>. Vamos mudar para um novo banco de dados chamado arraylab. O comando use cria o banco de dados se ele ainda não existir e muda o contexto atual para ele.

use arraylab

Agora, vamos inserir alguns documentos em uma nova coleção chamada products. Cada documento representa um produto e contém dois campos de array: tags e colors. Copie e cole o seguinte comando em seu shell:

db.products.insertMany([
  {
    name: "Laptop",
    tags: ["electronics", "computer", "work"],
    colors: ["silver", "black", "blue"]
  },
  {
    name: "Smartphone",
    tags: ["electronics", "mobile", "communication"],
    colors: ["red", "blue", "green"]
  },
  {
    name: "Headphones",
    tags: ["electronics", "audio", "music"],
    colors: ["black", "white"]
  }
]);

Para encontrar um documento que contenha um elemento específico em um array, você pode consultar diretamente esse valor. Esta consulta encontra todos os produtos que possuem a tag "mobile".

db.products.find({ tags: "mobile" });

Exemplo de Saída:

[
  {
    _id: ObjectId("..."),
    name: 'Smartphone',
    tags: [ 'electronics', 'mobile', 'communication' ],
    colors: [ 'red', 'blue', 'green' ]
  }
]

Você também pode encontrar documentos onde o array corresponde a uma sequência exata de elementos. Esta consulta encontra o produto cujo array tags é exatamente ["electronics", "computer", "work"] nessa ordem específica.

db.products.find({ tags: ["electronics", "computer", "work"] });

Exemplo de Saída:

[
  {
    _id: ObjectId("..."),
    name: 'Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    colors: [ 'silver', 'black', 'blue' ]
  }
]

Você pode permanecer no shell mongosh para as próximas etapas. Para sair do shell a qualquer momento, digite exit e pressione Enter.

Utilizando Operadores de Consulta de Array $all e $in

A correspondência simples é útil, mas o MongoDB oferece operadores poderosos para consultas de array mais complexas. Nesta etapa, você aprenderá a usar $all para corresponder a múltiplos elementos, independentemente da ordem, e $in para corresponder a qualquer um de uma lista de elementos.

Continuaremos usando a coleção products da etapa anterior.

O operador $all seleciona documentos onde o campo de array contém todos os elementos especificados. A ordem dos elementos na consulta não importa. Vamos encontrar produtos que estão disponíveis em "blue" e "silver".

db.products.find({ colors: { $all: ["blue", "silver"] } });

Exemplo de Saída:

[
  {
    _id: ObjectId("..."),
    name: 'Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    colors: [ 'silver', 'black', 'blue' ]
  }
]

O operador $in seleciona documentos onde o campo de array contém pelo menos um dos valores especificados. Ele funciona como uma condição "OU" para elementos de array. Vamos encontrar produtos que tenham a tag "music" ou a tag "work".

db.products.find({ tags: { $in: ["music", "work"] } });

Exemplo de Saída:

[
  {
    _id: ObjectId("..."),
    name: 'Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    colors: [ 'silver', 'black', 'blue' ]
  },
  {
    _id: ObjectId("..."),
    name: 'Headphones',
    tags: [ 'electronics', 'audio', 'music' ],
    colors: [ 'black', 'white' ]
  }
]

Esses operadores oferecem muito mais flexibilidade ao pesquisar documentos com base no conteúdo de seus arrays.

Consultando por Tamanho e Posição de Array

Às vezes, o número de elementos em um array ou a posição de um elemento específico é importante. Esta etapa abrange como consultar com base no tamanho do array usando o operador $size e por posição de elemento usando notação de ponto.

O operador $size corresponde a documentos que possuem um array com um número específico de elementos. Vamos encontrar produtos que têm exatamente duas cores disponíveis.

db.products.find({ colors: { $size: 2 } });

Exemplo de Saída:

[
  {
    _id: ObjectId("..."),
    name: 'Headphones',
    tags: [ 'electronics', 'audio', 'music' ],
    colors: [ 'black', 'white' ]
  }
]

Para consultar um elemento em uma posição específica (índice) em um array, você usa a notação de ponto no formato "fieldName.index". Lembre-se que os índices de array são baseados em zero, então o primeiro elemento está no índice 0. Esta consulta encontra todos os produtos onde o primeiro elemento no array tags é "electronics".

db.products.find({ "tags.0": "electronics" });

Exemplo de Saída:

[
  {
    _id: ObjectId("..."),
    name: 'Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    colors: [ 'silver', 'black', 'blue' ]
  },
  {
    _id: ObjectId("..."),
    name: 'Smartphone',
    tags: [ 'electronics', 'mobile', 'communication' ],
    colors: [ 'red', 'blue', 'green' ]
  },
  {
    _id: ObjectId("..."),
    name: 'Headphones',
    tags: [ 'electronics', 'audio', 'music' ],
    colors: [ 'black', 'white' ]
  }
]

Agora, vamos encontrar um produto onde a segunda cor (índice 1) é "black".

db.products.find({ "colors.1": "black" });

Exemplo de Saída:

[
  {
    _id: ObjectId("..."),
    name: 'Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    colors: [ 'silver', 'black', 'blue' ]
  }
]

Consultando Arrays de Documentos Embutidos

Um padrão comum e poderoso no MongoDB é ter arrays que contêm outros documentos. Estes são conhecidos como documentos embutidos ou aninhados. Consultar estes requer um operador especial, $elemMatch, para garantir que todas as condições se apliquem ao mesmo elemento do array.

Primeiro, vamos adicionar alguns novos produtos que possuem um array specs. Cada elemento no array specs é um documento com os campos ram, storage e price.

db.products.insertMany([
  {
    name: "Gaming Laptop",
    tags: ["electronics", "computer", "gaming"],
    specs: [
      { ram: 16, storage: 512, price: 1200 },
      { ram: 32, storage: 1024, price: 2000 }
    ]
  },
  {
    name: "Office Laptop",
    tags: ["electronics", "computer", "work"],
    specs: [
      { ram: 8, storage: 256, price: 600 },
      { ram: 16, storage: 512, price: 800 }
    ]
  }
]);

Agora, suponha que queremos encontrar um laptop que tenha uma configuração com pelo menos 16GB de RAM e um preço inferior a $1000. Uma consulta simples pode parecer correta, mas pode levar a resultados errados. Por exemplo, db.products.find({ "specs.ram": { $gte: 16 }, "specs.price": { $lt: 1000 } }) corresponderia a um documento se um documento embutido tivesse RAM suficiente e um diferente tivesse um preço baixo o suficiente.

Para garantir que um único documento embutido no array satisfaça todas as condições, você deve usar o operador $elemMatch.

db.products.find({
  specs: {
    $elemMatch: { ram: { $gte: 16 }, price: { $lt: 1000 } }
  }
});

Esta consulta encontra corretamente apenas o "Office Laptop", pois ele possui um elemento de especificação { ram: 16, storage: 512, price: 800 } que atende a ambas as condições simultaneamente.

Exemplo de Saída:

[
  {
    _id: ObjectId("..."),
    name: 'Office Laptop',
    tags: [ 'electronics', 'computer', 'work' ],
    specs: [
      { ram: 8, storage: 256, price: 600 },
      { ram: 16, storage: 512, price: 800 }
    ]
  }
]

Projetando Campos de Array

Frequentemente, você não precisa do documento inteiro retornado por uma consulta. A projeção permite que você especifique quais campos incluir ou excluir. Para arrays, o MongoDB fornece operadores de projeção especiais como $slice para controlar quais elementos do array são retornados.

O operador de projeção $slice retorna um subconjunto de um array. Você pode especificar um número positivo para obter os primeiros N elementos, ou um número negativo para obter os últimos N elementos.

Vamos recuperar todos os produtos, mas retornar apenas o name e as duas primeiras tags para cada um. O primeiro argumento para find, {}, é um documento de consulta vazio que corresponde a todos os documentos. O segundo argumento é o documento de projeção. Usamos _id: 0 para excluir o campo _id padrão.

db.products.find({}, { name: 1, tags: { $slice: 2 }, _id: 0 });

Exemplo de Saída:

[
  { "name": "Laptop", "tags": ["electronics", "computer"] },
  { "name": "Smartphone", "tags": ["electronics", "mobile"] },
  { "name": "Headphones", "tags": ["electronics", "audio"] },
  { "name": "Gaming Laptop", "tags": ["electronics", "computer"] },
  { "name": "Office Laptop", "tags": ["electronics", "computer"] }
]

Outro operador de projeção útil é o operador posicional $. Quando você consulta um array, este operador garante que apenas o primeiro elemento que correspondeu à condição da consulta seja retornado no campo de array projetado.

Vamos encontrar produtos com a tag "mobile" e retornar apenas o name e essa tag correspondente específica do array tags.

db.products.find({ tags: "mobile" }, { name: 1, "tags.$": 1, _id: 0 });

Exemplo de Saída:

[{ "name": "Smartphone", "tags": ["mobile"] }]

Isso é muito eficiente para recuperar apenas as partes relevantes de um array grande sem ter que processar o array completo em sua aplicação.

Resumo

Neste laboratório, você aprendeu as técnicas fundamentais para consultar arrays no MongoDB. Você começou com a correspondência básica de elementos e progrediu para o uso de operadores de array poderosos como $all, $in e $size. Você também explorou como consultar pela posição de um elemento e como consultar corretamente arrays de documentos embutidos usando $elemMatch. Finalmente, você aprendeu como moldar a saída de suas consultas projetando elementos de array específicos usando $slice e o operador posicional $. Essas habilidades são essenciais para gerenciar e recuperar dados de estruturas de documentos complexas no MongoDB de forma eficaz.