Docs Menu
Docs Home
/ /
Servicios de aplicaciones Atlas

Consulta MongoDB - SDK de Node.js

Puede consultar datos almacenados en MongoDB Atlas directamente desde el código de su aplicación cliente utilizando el SDK Node.js de Realm Cliente MongoDB con la API de consulta. Atlas App Services proporciona reglas de acceso a datos en colecciones para recuperar resultados de forma segura según el usuario conectado o el contenido de cada documento.

Nota

Conjunto de datos de ejemplo

Los ejemplos de esta página utilizan una colección de MongoDB que describe el inventario de una cadena de almacenes de plantas. Para obtener más información sobre el esquema de la colección y el contenido del documento, consulte Datos de ejemplo.

Existen variedad de razones por las que podría querer query una fuente de datos de MongoDB. Trabajar con datos en tu cliente a través de Atlas Device Sync no siempre es práctico o posible. Podrías querer query MongoDB cuando:

  • El conjunto de datos es grande o el dispositivo cliente tiene restricciones para cargar todo el conjunto de datos

  • Está creando o actualizando datos de usuario personalizados

  • Estás recuperando documentos que no están modelados en Realm

  • Su aplicación necesita acceder a colecciones que no tienen esquemas estrictos

  • Un servicio que no es de Realm genera colecciones a las que desea acceder

Si bien no son exhaustivos, estos son algunos casos de uso comunes para consultar MongoDB directamente.

Antes de poder consultar MongoDB desde su aplicación Node.js, debe configurar el acceso a datos de MongoDB en su aplicación de App Services. Para saber cómo configurar su aplicación backend para que el SDK de Realm pueda consultar Atlas, consulte "Configurar el acceso a datos de MongoDB" en la documentación de App Services.

Ejemplo

Datos de ejemplo

Los ejemplos de esta página utilizan la siguiente colección MongoDB que describe varias plantas a la venta en una cadena de tiendas 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" }

Documentos en el plants La colección utiliza el siguiente 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 acceder a un clúster vinculado desde su aplicación cliente, pase el nombre del clúster a User.mongoClient(). Esto devuelve una interfaz de servicio MongoDB que puede usar para acceder a las bases de datos y colecciones del clúster.

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 un solo documento, envíe una consulta que coincida con el documento a collection.findOne(). Si no envía ninguna consulta, findOne() coincide con el primer documento que encuentre en la colección.

El siguiente fragmento encuentra el documento que describe las plantas "Venus atrapamoscas" en la colección de documentos que describen plantas a la venta en un grupo de tiendas:

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 encontrar varios documentos, envíe una consulta que coincida con los documentos a collection.find(). Si no envía ninguna consulta, find() coincide con todos los documentos de la colección.

El siguiente fragmento encuentra todos los documentos que describen plantas perennes en la colección de documentos que describen plantas en venta en un grupo de tiendas:

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, pase una consulta que coincida con los documentos a collection.count(). Si no pasa ninguna consulta, count() cuenta todos los documentos de la colección.

El siguiente fragmento cuenta la cantidad de documentos en una colección de documentos que describen plantas en venta en un grupo de tiendas:

const numPlants = await plants.count();
console.log(`There are ${numPlants} plants in the collection`);
"There are 9 plants in the collection"

Para insertar un solo documento, páselo a collection.insertOne().

El siguiente fragmento inserta un único documento que describe una planta de "lirio de los valles" en una colección de documentos que describen plantas a la venta en un grupo de tiendas:

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 insertar varios documentos al mismo tiempo, páselos como una matriz a collection.insertMany().

El siguiente fragmento inserta tres documentos que describen plantas en una colección de documentos que describen plantas en venta en un grupo de tiendas:

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 actualizar un solo documento, pase una consulta que coincida con el documento y un documento de actualización a collection.updateOne().

El siguiente fragmento actualiza un documento de una colección que describe plantas a la venta en un grupo de tiendas. Esta operación busca un documento cuyo name campo contiene el valor "petunia" y cambia el valor del campo del primer documento coincidente sunlight a "parcial":

const result = await plants.updateOne(
{ name: "petunia" },
{ $set: { sunlight: "partial" } }
);
console.log(result);
{ matchedCount: 1, modifiedCount: 1 }

Para actualizar varios documentos al mismo tiempo, pasar una query que coincida con los documentos y una descripción de actualizar a colección.updateMany().

El siguiente fragmento actualiza varios documentos de una colección que describen plantas en venta en un grupo de tiendas. Esta operación busca documentos cuyo _partition campo contenga el valor "Tienda 47" y cambia el valor del _partition campo de cada documento coincidente a "Tienda 51":

const result = await plants.updateMany(
{ _partition: "Store 47" },
{ $set: { _partition: "Store 51" } }
);
console.log(result);
{ matchedCount: 3, modifiedCount: 3 }

Para hacer una inserción de un documento, configure la opción upsert en true en su operación de actualización. Si la query de la operación no coincide con ningún documento en la colección, una inserción inserta automáticamente un nuevo documento único en la colección que coincide con el documento de query proporcionado con la actualización aplicada a este.

El siguiente fragmento actualiza un documento de una colección que describe plantas en venta en un grupo de tiendas mediante una operación upsert. La consulta no coincide con ningún documento existente, por lo que MongoDB crea uno nuevo automáticamente.

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 eliminar un solo documento de una colección, pase una consulta que coincida con el documento a collection.deleteOne(). Si no pasa una consulta o si esta coincide con varios documentos, la operación elimina el primer documento que encuentra.

El siguiente fragmento elimina un documento de una colección que describe plantas en venta en un grupo de tiendas. Esta operación busca un documento cuyo color campo tenga el valor "verde" y elimina el primer documento que coincida con la consulta:

const result = await plants.deleteOne({ color: "green" });
console.log(result);
{ deletedCount: 1 }

Para eliminar varios documentos de una colección, pase una consulta que coincida con los documentos a collection.deleteMany(). Si no pasa ninguna consulta, deleteMany() elimina todos los documentos de la colección.

El siguiente fragmento elimina todos los documentos de plantas que se encuentran en "Tienda 51" en una colección de documentos que describen plantas en venta en un grupo de tiendas:

const result = await plants.deleteMany({
_partition: "Store 51",
});
console.log(result);
{ deletedCount: 3 }

Puedes llamar a collection.watch() para suscribirte a las notificaciones de cambios en tiempo real que MongoDB emite cada vez que se añade, modifica o elimina un documento de la colección. Cada notificación especifica el documento modificado, cómo se modificó y el documento completo después de la operación que provocó el evento.

Importante

Limitaciones de la tecnología sin servidor

No puedes observar cambios si la fuente de datos es una instancia sin servidor de Atlas. El servidor sin servidor de MongoDB actualmente no admite flujos de cambios, que se emplean en las colecciones monitoreadas para escuchar cambios.

Para observar todos los cambios en una colección, llame a collection.watch() sin 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 cambios específicos en una colección, pase una consulta que coincida con los campos de eventos de cambio a 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);
}

Las operaciones de agregación ejecutan todos los documentos de una colección a través de una serie de etapas denominadas canalización de agregación. La agregación permite filtrar y transformar documentos, recopilar datos resumidos sobre grupos de documentos relacionados y realizar otras operaciones complejas con datos.

Para ejecutar una canalización de agregación, pase una matriz de etapas de agregación a collection.aggregate(). Las operaciones de agregación devuelven el conjunto de resultados de la última etapa de la canalización.

El siguiente fragmento agrupa todos los documentos de la colección plants por su valor type y agrega un recuento de la cantidad 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 },
]

Puede utilizar la etapa $match para filtrar documentos según la sintaxis de consulta estándar de MongoDB.

{
"$match": {
"<Field Name>": <Query Expression>,
...
}
}

Ejemplo

El siguiente filtro de etapa $match filtra documentos para incluir solo aquellos donde el campo type tenga un valor igual a "perenne":

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

Puede usar la etapa $group para agregar datos de resumen de uno o más documentos. MongoDB agrupa documentos según la expresión definida en el _id campo de la $group etapa. Puede hacer referencia a un campo de documento específico anteponiendo al nombre del $ campo.

{
"$group": {
"_id": <Group By Expression>,
"<Field Name>": <Aggregation Expression>,
...
}
}

Ejemplo

La siguiente etapa $group organiza los documentos por valor de su campo type y calcula la cantidad de documentos de plantas en los que cada valor único type 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, puede usar consultas de agregación de rangos con los $match $sortoperadores,$limit y. Para obtener más información sobre la paginación de documentos, consulte "Uso de consultas de rangos" en la documentación de MongoDB Server.

Ejemplo

El siguiente ejemplo pagina una colección de documentos en orden ascendente.

// 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

Puede usar la etapa $project para incluir u omitir campos específicos de los documentos o para calcular nuevos campos mediante operadores de agregación. Las proyecciones funcionan de dos maneras:

  • Incluir explícitamente los campos con el valor 1. Esto tiene el efecto secundario de excluir implícitamente todos los campos no especificados.

  • Excluye implícitamente los campos con un valor de 0. Esto tiene el efecto secundario de incluir implícitamente todos los campos no especificados.

Estos dos métodos de proyección son mutuamente excluyentes: si incluye campos explícitamente, no puede excluirlos explícitamente, y viceversa.

Nota

El _id campo es un caso especial: siempre se incluye en todas las consultas, a menos que se especifique lo contrario. Por esta razón, se puede excluir el _id campo con un 0 valor e incluir simultáneamente otros campos,_partition como, con un 1 valor. Solo el caso especial de exclusión del _id campo permite tanto la exclusión como la inclusión en una sola $project etapa.

{
"$project": {
"<Field Name>": <0 | 1 | Expression>,
...
}
}

Ejemplo

La siguiente etapa $project omite el campo _id, incluye el campo name y crea un nuevo campo llamado storeNumber. El storeNumber se genera mediante dos operadores de agregación:

  1. $split Separa el valor _partition en dos segmentos de cadena que rodean el espacio. Por ejemplo, el valor "Store 42" dividido de esta manera devuelve una matriz con dos elementos: "Store" y "42".

  2. $arrayElemAt Selecciona un elemento específico de un array según el segundo argumento. En este caso, el valor 1 selecciona el segundo elemento del array generado por el operador $split, ya que los arrays indexan desde 0. Por ejemplo, el valor ["Store", "42"] pasado a esta operación devolvería un 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" }
]

Puede utilizar la etapa $addFields para agregar nuevos campos con valores calculados utilizando operadores de agregación.

{ $addFields: { <newField>: <expression>, ... } }

Nota

$addFields es similar a $project pero no permite incluir u omitir campos.

Ejemplo

La siguiente etapa $addFields crea un nuevo campo llamado storeNumber donde el valor es la salida de dos operadores agregados que transforman el valor del 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" }
]

Puede usar la etapa $unwind para transformar un documento que contiene una matriz en varios documentos que contienen valores individuales de esa matriz. Al desenrollar un campo de matriz, MongoDB copia cada documento una vez por cada elemento de dicho campo, pero reemplaza el valor de la matriz con el elemento de la matriz en cada copia.

{
$unwind: {
path: <Array Field Path>,
includeArrayIndex: <string>,
preserveNullAndEmptyArrays: <boolean>
}
}

Ejemplo

El siguiente ejemplo utiliza la etapa $unwind para la combinación type y color de cada objeto. La canalización de agregación consta de los siguientes pasos:

  1. Utilice la etapa $group con $addToSet para crear nuevos documentos para cada type con un nuevo campo colors que contenga una matriz de todos los colores para ese tipo de flor que aparecen en la colección.

  2. Utilice la etapa $unwind para crear documentos separados para cada combinación de tipo y color.

  3. Utilice la etapa $sort para ordenar los resultados en orden alfabético.

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

Volver

Llamar a una función