Query MongoDB - Node.js SDK
Nesta página
- Casos de uso
- Pré-requisitos
- Conectar a um cluster vinculado
- Ler operações
- Encontrar um único documento
- Localizar vários documentos
- Contagem de documentos
- Operações de Escrita
- Inserir um único documento
- Insira vários documentos
- Atualizar um único documento
- Atualizar vários documentos
- Documentos do Upsert
- Excluir um único documento
- Excluir vários documentos
- Notificações de alterações em tempo real
- Fique atento a todas as alterações em uma coleção
- Fique atento a mudanças específicas em uma collection
- Operações de agregação
- Execute um Pipeline de Agregação
Você pode fazer query dos dados armazenados no MongoDB Atlas diretamente do código do seu aplicação cliente usando ocliente MongoDB do Realm Node.js SDK com a API de Query. O Atlas App Services fornece regras de acesso a dados em coleções para recuperar resultados com segurança com base no usuário conectado ou no conteúdo de cada documento.
Observação
Conjunto de Dados de Exemplo
Os exemplos nesta página usam uma coleção MongoDB que descreve o inventário em uma cadeia de lojas de plantas. Para obter mais informações sobre o esquema de coleção e o conteúdo do documento, consulte Exemplo de dados.
Casos de uso
Existem várias razões pelas quais você pode querer fazer uma query em uma fonte de dados MongoDB. Trabalhar com dados em seu cliente via Atlas Device Sync nem sempre é prático ou possível. Talvez você queira fazer uma query no MongoDB quando:
O conjunto de dados for grande ou o dispositivo cliente tiver restrições para carregar todo o conjunto de dados
Você estiver criando ou atualizando dados de usuário personalizados
Você estiver recuperando documentos que não sejam modelados no Realm
Sua aplicação precisa acessar collections que não têm esquemas rigorosos
Um serviço que não é do Realm gera coleções que você deseja acessar
Embora não exaustivos, esses são alguns casos de uso comuns para a query direta do MongoDB.
Pré-requisitos
Antes de fazer a query no MongoDB a partir do seu aplicativo Node.js, você deve definir o MongoDB Data Access no seu App Services App. Para saber como configurar seu aplicativo de backend para permitir que o Realm SDK consulte o Atlas, consulte Configurar o acesso aos dados do MongoDB na documentação do Atlas App Services .
Exemplo
Dados de exemplo
Os exemplos nesta página usam a seguinte coleção MongoDB que descreve várias plantas para venda em uma cadeia de lojas de plantas:
{ _id: ObjectId("5f87976b7b800b285345a8c4"), name: "venus flytrap", sunlight: "full", color: "white", type: "perennial", _partition: "Store 42" }, { _id: ObjectId("5f87976b7b800b285345a8c5"), name: "sweet basil", sunlight: "partial", color: "green", type: "annual", _partition: "Store 42" }, { _id: ObjectId("5f87976b7b800b285345a8c6"), name: "thai basil", sunlight: "partial", color: "green", type: "perennial", _partition: "Store 42" }, { _id: ObjectId("5f87976b7b800b285345a8c7"), name: "helianthus", sunlight: "full", color: "yellow", type: "annual", _partition: "Store 42" }, { _id: ObjectId("5f87976b7b800b285345a8c8"), name: "petunia", sunlight: "full", color: "purple", type: "annual", _partition: "Store 47" }
Os documentos na coleção plants
utilizam o seguinte esquema:
{ "title": "Plant", "bsonType": "object", "required": ["_id", "_partition", "name"], "properties": { "_id": { "bsonType": "objectId" }, "_partition": { "bsonType": "string" }, "name": { "bsonType": "string" }, "sunlight": { "bsonType": "string" }, "color": { "bsonType": "string" }, "type": { "bsonType": "string" } } }
type Plant = { _id: BSON.ObjectId; _partition: string; name: string; sunlight?: string; color?: string; type?: string; };
Conectar a um cluster vinculado
Para acessar um cluster vinculado do aplicativo cliente, passe o nome do cluster para User.mongoClient(). Isso retorna uma interface do serviço MongoDB que pode ser usada para acessar bases de dados e coleção no cluster.
const mongodb = app.currentUser.mongoClient("mongodb-atlas"); const plants = mongodb.db("example").collection("plants");
const mongodb = app.currentUser.mongoClient("mongodb-atlas"); const plants = mongodb.db("example").collection<Plant>("plants");
Ler operações
Encontrar um único documento
Para encontrar um único documento, faça uma query que corresponda ao documento para coleção.findOne(). Se você não fizer uma query, findOne()
corresponderá ao primeiro documento encontrado na coleção.
O trecho a seguir encontra o documento que descreve as plantas "dioneia" na coleção de documentos que descrevem plantas à venda em um grupo de lojas:
const venusFlytrap = await plants.findOne({ name: "venus flytrap" }); console.log("venusFlytrap", venusFlytrap);
{ _id: ObjectId("5f87976b7b800b285345a8c4"), name: "venus flytrap", sunlight: "full", color: "white", type: "perennial", _partition: "Store 42", }
Localizar vários documentos
Para localizar vários documentos, faça uma query que corresponda aos documentos para coleção.find(). Se você não passar uma query, find()
corresponderá a todos os documentos da coleção.
O seguinte trecho encontra todos os documentos que descrevem plantas perenes na coleção de documentos que descrevem plantas para venda em um grupo de lojas:
const perennials = await plants.find({ type: "perennial" }); console.log("perennials", perennials);
[ { _id: ObjectId("5f87976b7b800b285345a8c4"), name: 'venus flytrap', sunlight: 'full', color: 'white', type: 'perennial', _partition: 'Store 42' }, { _id: ObjectId("5f87976b7b800b285345a8c6"), name: 'thai basil', sunlight: 'partial', color: 'green', type: 'perennial', _partition: 'Store 42' }, { _id: ObjectId("5f879f83fc9013565c23360e"), name: 'lily of the valley', sunlight: 'full', color: 'white', type: 'perennial', _partition: 'Store 47' }, { _id: ObjectId("5f87a0defc9013565c233611"), name: 'rhubarb', sunlight: 'full', color: 'red', type: 'perennial', _partition: 'Store 47' }, { _id: ObjectId("5f87a0dffc9013565c233612"), name: 'wisteria lilac', sunlight: 'partial', color: 'purple', type: 'perennial', _partition: 'Store 42' }, { _id: ObjectId("5f87a0dffc9013565c233613"), name: 'daffodil', sunlight: 'full', color: 'yellow', type: 'perennial', _partition: 'Store 42' } ]
Contagem de documentos
Para contar documentos, passe uma query que corresponda aos documentos para collection.count(). Se você não passar uma query, count()
contará todos os documentos na collection.
O seguinte trecho conta o número de documentos em uma coleção de documentos que descrevem plantas para venda em um grupo de lojas:
const numPlants = await plants.count(); console.log(`There are ${numPlants} plants in the collection`);
"There are 9 plants in the collection"
Operações de Escrita
Inserir um único documento
Para inserir um único documento, passe para collection.insertOne().
O trecho a seguir insere um único documento que descreve uma planta "lírio do vale" em uma coleção de documentos que descrevem plantas à venda em um grupo de lojas:
const result = await plants.insertOne({ name: "lily of the valley", sunlight: "full", color: "white", type: "perennial", _partition: "Store 47", }); console.log(result);
{ insertedId: "5f879f83fc9013565c23360e", }
Insira vários documentos
Para inserir vários documentos ao mesmo tempo, passe-os como uma array para collection.insertMany().
O trecho a seguir insere três documentos descrevendo plantas em uma coleção de documentos que descrevem plantas para venda em um grupo de lojas:
const result = await plants.insertMany([ { name: "rhubarb", sunlight: "full", color: "red", type: "perennial", _partition: "Store 47", }, { name: "wisteria lilac", sunlight: "partial", color: "purple", type: "perennial", _partition: "Store 42", }, { name: "daffodil", sunlight: "full", color: "yellow", type: "perennial", _partition: "Store 42", }, ]); console.log(result);
{ insertedIds: [ "5f87a0defc9013565c233611", "5f87a0dffc9013565c233612", "5f87a0dffc9013565c233613", ], }
Atualizar um único documento
Para atualizar um único documento, passe uma query que corresponda ao documento e um documento de atualização para collection.updateOne().
O trecho a seguir atualiza um único documento em uma coleção de documentos que descrevem plantas para venda em um grupo de lojas. Essa operação consulta um documento em que o campo name
contém o valor "petunia" e altera o valor do campo sunlight
do primeiro documento correspondente para "parcial":
const result = await plants.updateOne( { name: "petunia" }, { $set: { sunlight: "partial" } } ); console.log(result);
{ matchedCount: 1, modifiedCount: 1 }
Atualizar vários documentos
Para atualizar vários documentos simultaneamente, faça uma query que corresponda aos documentos e uma descrição de atualização para collection.updateMany().
O trecho a seguir atualiza vários documentos em uma coleção de documentos que descrevem plantas para venda em um grupo de lojas. Esta operação faz queries em documentos onde o campo _partition
contém o valor "Armazenar 47" e altera o valor do campo _partition
de cada documento correspondente para "Armazenar 51":
const result = await plants.updateMany( { _partition: "Store 47" }, { $set: { _partition: "Store 51" } } ); console.log(result);
{ matchedCount: 3, modifiedCount: 3 }
Documentos do Upsert
Para atualizar um documento, defina a opção upsert
para true
na sua operação de atualização. Se a query da operação não corresponder a nenhum documento na coleção, um upsert inserirá automaticamente um único novo documento na coleção que corresponda ao documento de query fornecido com a atualização aplicada a ele.
O trecho a seguir atualiza um documento em uma coleção de documentos que descrevem plantas para venda em um grupo de lojas com uma operação de upsert. A query não corresponde a nenhum documento existente, portanto, o MongoDB cria automaticamente um novo.
const result = await plants.updateOne( { sunlight: "full", type: "perennial", color: "green", _partition: "Store 47", }, { $set: { name: "sweet basil" } }, { upsert: true } ); console.log(result);
{ matchedCount: 0, modifiedCount: 0, upsertedId: ObjectId("5f1f63055512f2cb67f460a3"), }
Excluir um único documento
Para excluir um único documento de uma coleção, faça uma query que corresponda ao documento para collection.deleteOne(). Se você não fizer uma query ou se a query corresponder a vários documentos, a operação excluirá o primeiro documento encontrado.
O trecho a seguir exclui um documento em uma coleção de documentos que descrevem plantas para venda em um grupo de lojas. Esta operação consulta um documento onde o campo color
tem um valor de "verde" e exclui o primeiro documento que corresponde à consulta:
const result = await plants.deleteOne({ color: "green" }); console.log(result);
{ deletedCount: 1 }
Excluir vários documentos
Para excluir vários documentos de uma coleção, faça uma query que corresponda aos documentos para coleção.deleteMany(). Se você não fizer uma query, o deleteMany()
excluirá todos os documentos na coleção.
O snippet a seguir exclui todos os documentos para plantas que estão em "Loja 51" em uma coleção de documentos que descrevem plantas para venda em um grupo de lojas:
const result = await plants.deleteMany({ _partition: "Store 51", }); console.log(result);
{ deletedCount: 3 }
Notificações de alterações em tempo real
Você pode chamar collection.watch() para se inscrever nas notificações de alteração em tempo real que o MongoDB emite sempre que um documento da coleção é adicionado, modificado ou excluído. Cada notificação especifica um documento que foi alterado, como ele foi alterado e o documento completo após a operação que causou o evento.
Observação
collection.watch()
retorna um gerador assíncrono que permite que você extraia de forma assíncrona eventos de alteração para operações à medida que ocorrem.
Importante
Limitações sem servidor
Você não poderá observar alterações se a fonte de dados for uma instância sem servidor do Atlas. Atualmente, o MongoDB serverless não oferece suporte a fluxos de alterações, que são usados em coleções monitoradas para escutar alterações.
Fique atento a todas as alterações em uma coleção
Para observar todas as alterações em uma coleção, chame collection.watch() sem argumentos:
for await (const change of plants.watch()) { switch (change.operationType) { case "insert": { const { documentKey, fullDocument } = change; console.log(`new document: ${documentKey}`, fullDocument); break; } case "update": { const { documentKey, fullDocument } = change; console.log(`updated document: ${documentKey}`, fullDocument); break; } case "replace": { const { documentKey, fullDocument } = change; console.log(`replaced document: ${documentKey}`, fullDocument); break; } case "delete": { const { documentKey } = change; console.log(`deleted document: ${documentKey}`); break; } } }
Fique atento a mudanças específicas em uma collection
Para observar alterações específicas em uma coleção, faça uma query que corresponda aos campos de eventos de alteração para collection.watch():
for await (const change of plants.watch({ filter: { operationType: "insert", "fullDocument.type": "perennial", }, })) { // The change event will always represent a newly inserted perennial const { documentKey, fullDocument } = change; console.log(`new document: ${documentKey}`, fullDocument); }
Operações de agregação
As operações de agregação executam todos os documentos em uma coleção por meio de uma série de etapas denominadas pipeline de agregação. A agregação permite filtrar e transformar documentos, coletar dados resumidos sobre grupos de documentos relacionados e outras operações de dados complexas.
Execute um Pipeline de Agregação
Para executar um pipeline de agregação, passe uma array de estágios de agregação para collection.aggregate(). As operações de agregação retornam o conjunto de resultados da última etapa do pipeline.
O trecho a seguir agrupa todos os documentos na coleção plants
por seu valor type
e agrega uma contagem do número de cada tipo:
const result = await plants.aggregate([ { $group: { _id: "$type", total: { $sum: 1 }, }, }, { $sort: { _id: 1 } }, ]); console.log(result);
[ { _id: "annual", total: 1 }, { _id: "perennial", total: 5 }, ]
Filtrar documentos
Você pode utilizar o estágio $match para filtrar documentos de acordo com a sintaxe da query padrão do MongoDB.
{ "$match": { "<Field Name>": <Query Expression>, ... } }
Exemplo
O seguinte estágio $match
filtra os documentos para incluir apenas aqueles em que o campo type
tem um valor igual a "perene":
const perennials = await plants.aggregate([ { $match: { type: { $eq: "perennial" } } }, ]); console.log(perennials);
[ { "_id": ObjectId("5f87976b7b800b285345a8c4"), "_partition": "Store 42", "color": "white", "name": "venus flytrap", "sunlight": "full", "type": "perennial" }, { "_id": ObjectId("5f87976b7b800b285345a8c6"), "_partition": "Store 42", "color": "green", "name": "thai basil", "sunlight": "partial", "type": "perennial" }, { "_id": ObjectId("5f87a0dffc9013565c233612"), "_partition": "Store 42", "color": "purple", "name": "wisteria lilac", "sunlight": "partial", "type": "perennial" }, { "_id": ObjectId("5f87a0dffc9013565c233613"), "_partition": "Store 42", "color": "yellow", "name": "daffodil", "sunlight": "full", "type": "perennial" }, { "_id": ObjectId("5f1f63055512f2cb67f460a3"), "_partition": "Store 47", "color": "green", "name": "sweet basil", "sunlight": "full", "type": "perennial" } ]
Documentos do grupo
Você pode usar o estágio $group para agregar dados resumidos de um ou mais documentos. O MongoDB agrupa documentos com base na expressão definida no campo _id
da etapa $group
. Você pode referenciar um campo de documento específico prefixando o nome do campo com um $
.
{ "$group": { "_id": <Group By Expression>, "<Field Name>": <Aggregation Expression>, ... } }
Exemplo
A etapa $group
a seguir organiza documentos pelo valor de seu campo type
e calcula o número de documentos da planta em que cada valor type
exclusivo aparece.
const result = await plants.aggregate([ { $group: { _id: "$type", numItems: { $sum: 1 }, }, }, { $sort: { _id: 1 } }, ]); console.log(result);
[ { _id: "annual", numItems: 1 }, { _id: "perennial", numItems: 5 }, ]
Paginar documentos
Para paginar resultados, você pode utilizar consultas de agregação de intervalo com os operadores $match
, $sort
e $limit
. Para saber mais sobre a paginação de documentos, consulte Usando consultas de intervalo na documentação do MongoDB Server.
Exemplo
O exemplo a seguir pagina em ordem crescente por meio de uma coleção de documentos.
// Paginates through list of plants // in ascending order by plant name (A -> Z) async function paginateCollectionAscending( collection, nPerPage, startValue ) { const pipeline = [{ $sort: { name: 1 } }, { $limit: nPerPage }]; // If not starting from the beginning of the collection, // only match documents greater than the previous greatest value. if (startValue !== undefined) { pipeline.unshift({ $match: { name: { $gt: startValue }, }, }); } const results = await collection.aggregate(pipeline); return results; } // Number of results to show on each page const resultsPerPage = 3; const pageOneResults = await paginateCollectionAscending( plants, resultsPerPage ); const pageTwoStartValue = pageOneResults[pageOneResults.length - 1].name; const pageTwoResults = await paginateCollectionAscending( plants, resultsPerPage, pageTwoStartValue ); // ... can keep paginating for as many plants as there are in the collection
Campos do documento do projeto
Você pode utilizar o estágio $project para incluir ou omitir campos específicos de documentos ou calcular novos campos utilizando operadores de agregação. As projeções funcionam de duas formas:
Inclua campos explicitamente com um valor de 1. Isso tem o efeito colateral de excluir implicitamente todos os campos não especificados.
Exclua campos de forma implícita com um valor de 0. Isso tem o efeito colateral de incluir implicitamente todos os campos não especificados.
Esses dois métodos de projeção são mutuamente exclusivos: se você incluir campos explicitamente, não poderá excluir campos explicitamente e vice-versa.
Observação
O campo _id
é um caso especial: ele é sempre incluído em todas as consultas, a menos que seja explicitamente especificado de outra forma. Por esse motivo, você pode excluir o campo _id
com um valor 0
e, ao mesmo tempo, incluir outros campos, como _partition
, com um 1
. Somente o caso especial de exclusão do campo _id
permite tanto a exclusão quanto a inclusão em um estágio $project
.
{ "$project": { "<Field Name>": <0 | 1 | Expression>, ... } }
Exemplo
O estágio $project
a seguir omite o campo _id
, inclui o campo name
e cria um novo campo chamado storeNumber
. O storeNumber
é gerado usando dois operadores de agregação:
$split
separa o valor_partition
em dois segmentos de string ao redor do caractere de espaço. Por exemplo, o valor "Store 42" dividido dessa forma retorna uma matriz com dois elementos: "Store" e "42".$arrayElemAt
seleciona um elemento específico de uma matriz com base no segundo argumento. Nesse caso, o valor1
seleciona o segundo elemento da matriz gerada pelo operador$split
, já que as matrizes são indexadas a partir de0
. Por exemplo, o valor ["Loja", "42"] passado para esta operação retornaria um valor de "42".
const result = await plants.aggregate([ { $project: { _id: 0, name: 1, storeNumber: { $arrayElemAt: [{ $split: ["$_partition", " "] }, 1], }, }, }, ]); console.log(result);
[ { "name": "venus flytrap", "storeNumber": "42" }, { "name": "thai basil", "storeNumber": "42" }, { "name": "helianthus", "storeNumber": "42" }, { "name": "wisteria lilac", "storeNumber": "42" }, { "name": "daffodil", "storeNumber": "42" }, { "name": "sweet basil", "storeNumber": "47" } ]
Adicionar campos aos documentos
Você pode usar o estágio $addFields para adicionar novos campos com valores calculados usando operadores de agregação.
{ $addFields: { <newField>: <expression>, ... } }
Observação
$addFields
é semelhante ao $project, mas não permite que você inclua ou omita campos.
Exemplo
O estágio $addFields
a seguir cria um novo campo chamado storeNumber
em que o valor é a saída de dois operadores agregados que transformam o valor do campo _partition
.
const result = await plants.aggregate([ { $addFields: { storeNumber: { $arrayElemAt: [{ $split: ["$_partition", " "] }, 1], }, }, }, ]); console.log(result);
[ { "_id": ObjectId("5f87976b7b800b285345a8c4"), "_partition": "Store 42", "color": "white", "name": "venus flytrap", "storeNumber": "42", "sunlight": "full", "type": "perennial" }, { "_id": ObjectId("5f87976b7b800b285345a8c6"), "_partition": "Store 42", "color": "green", "name": "thai basil", "storeNumber": "42", "sunlight": "partial", "type": "perennial" }, { "_id": ObjectId("5f87976b7b800b285345a8c7"), "_partition": "Store 42", "color": "yellow", "name": "helianthus", "storeNumber": "42", "sunlight": "full", "type": "annual" }, { "_id": ObjectId("5f87a0dffc9013565c233612"), "_partition": "Store 42", "color": "purple", "name": "wisteria lilac", "storeNumber": "42", "sunlight": "partial", "type": "perennial" }, { "_id": ObjectId("5f87a0dffc9013565c233613"), "_partition": "Store 42", "color": "yellow", "name": "daffodil", "storeNumber": "42", "sunlight": "full", "type": "perennial" }, { "_id": ObjectId("5f1f63055512f2cb67f460a3"), "_partition": "Store 47", "color": "green", "name": "sweet basil", "storeNumber": "47", "sunlight": "full", "type": "perennial" } ]
Unwind Array Values
Você pode usar o estágio $unwind para transformar um único documento contendo uma matriz em vários documentos contendo valores individuais dessa matriz. Quando você desenrola um campo de matriz, o MongoDB copia cada documento uma vez para cada elemento do campo de matriz, mas substitui o valor da matriz pelo elemento da matriz em cada cópia.
{ $unwind: { path: <Array Field Path>, includeArrayIndex: <string>, preserveNullAndEmptyArrays: <boolean> } }
Exemplo
O exemplo a seguir usa o estágio $unwind
para a combinação type
e color
de cada objeto. O pipeline de agregação tem as seguintes etapas:
Use a etapa
$group
com$addToSet
para criar novos documentos para cadatype
com um novo campocolors
que contenha uma matriz de todas as cores desse tipo de flor que ocorrem na coleção.Use o estágio
$unwind
para criar documentos separados para cada combinação de tipo e cor.Use o estágio
$sort
para classificar os resultados em ordem alfabética.
const result = await plants.aggregate([ { $group: { _id: "$type", colors: { $addToSet: "$color" } } }, { $unwind: { path: "$colors" } }, { $sort: { _id: 1, colors: 1 } }, ]); console.log(result);
[ { "_id": "annual", "colors": "yellow" }, { "_id": "perennial", "colors": "green" }, { "_id": "perennial", "colors": "purple" }, { "_id": "perennial", "colors": "white" }, { "_id": "perennial", "colors": "yellow" }, ]