Menu Docs
Página inicial do Docs
/ /
Atlas Device SDKs
/ /

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.

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.

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;
};

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");

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",
}

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' }
]

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"

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",
}

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",
],
}

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 }

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 }

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"),
}

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 }

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 }

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.

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;
}
}
}

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);
}

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.

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 },
]

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" }
]

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 },
]

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

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:

  1. $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".

  2. $arrayElemAt seleciona um elemento específico de uma matriz com base no segundo argumento. Nesse caso, o valor 1 seleciona o segundo elemento da matriz gerada pelo operador $split, já que as matrizes são indexadas a partir de 0. 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" }
]

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" }
]

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:

  1. Use a etapa $group com $addToSet para criar novos documentos para cada type com um novo campo colors que contenha uma matriz de todas as cores desse tipo de flor que ocorrem na coleção.

  2. Use o estágio $unwind para criar documentos separados para cada combinação de tipo e cor.

  3. 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" },
]

Voltar

Chamar uma função