Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /
Atlas App Services

Consulta MongoDB - SDK de React Native

Puede consultar datos almacenados en MongoDB Atlas directamente desde el código de su aplicación cliente utilizando el SDK de Realm React Native. 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:

  • The data set is large or the client device has constraints against loading the entire data set

  • You are creating or updating custom user data

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

  • Your app needs to access collections that don't have strict schemas

  • A non-Realm service generates collections that you want to access

While not exhaustive, these are some common use cases for querying MongoDB directly.

Antes de poder consultar MongoDB desde su aplicación React Native, 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 en esta página usan 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;
};

To access a linked cluster from your client application, authenticate a user and pass the cluster name to User.mongoClient(). This returns a MongoDB service interface that you can use to access databases and collections in the cluster.

If you are using @realm/react, you can access the MongoDB client with the useUser() hook in a component wrapped by UserProvider.

import React from 'react';
import {useUser} from '@realm/react';
function QueryPlants() {
// Get currently logged in user
const user = useUser();
const getPlantByName = async name => {
// Access linked MongoDB collection
const mongodb = user.mongoClient('mongodb-atlas');
const plants = mongodb.db('example').collection('plants');
// Query the collection
const response = await plants.findOne({name});
return response;
};
// ...
}
import React from 'react';
import {useUser} from '@realm/react';
function QueryPlants() {
// Get currently logged in user
const user = useUser();
const getPlantByName = async (name: string) => {
// Access linked MongoDB collection
const mongodb = user.mongoClient('mongodb-atlas');
const plants = mongodb.db('example').collection<Plant>('plants');
// Query the collection
const response = await plants.findOne({name});
return response;
};
// ...
}

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 snippet encuentra el documento que describe las plantas "venus atrapamoscas" en la colección de documentos que describen plantas en 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, pasa una query que coincida con los documentos a colección.count(). Si no pasa un query, 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ásalo a collection.insertOne().

The following snippet inserts a single document describing a "lily of the valley" plant into a collection of documents that describe plants for sale in a group of stores:

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().

The following snippet updates a single document in a collection of documents that describe plants for sale in a group of stores. This operation queries for a document where the name field contains the value "petunia" and changes the value of the first matched document's sunlight field to "partial":

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, pasa una consulta que coincida con el documento a collection.deleteOne(). Si no se pasa una query o si la query coincide con varios documentos, la operación borra el primer documento que encuentra.

The following snippet deletes one document in a collection of documents that describe plants for sale in a group of stores. This operation queries for a document where the color field has a value of "green" and deletes the first document that matches the query:

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

To delete multiple document from a collection, pass a query that matches the documents to collection.deleteMany(). If you do not pass a query, deleteMany() deletes all documents in the collection.

The following snippet deletes all documents for plants that are in "Store 51" in a collection of documents that describe plants for sale in a group of stores:

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

You can call collection.watch() to subscribe to real-time change notifications that MongoDB emits whenever a document in the collection is added, modified, or deleted. Each notification specifies a document that changed, how it changed, and the full document after the operation that caused the event.

collection.watch() devuelve un generador asíncronoque le permite extraer de forma asincrónica eventos de cambio para las operaciones a medida que ocurren.

collection.watch() Requiere cierta configuración para funcionar con una aplicación cliente de React Native. Para supervisar los cambios en una colección, primero debe instalar los paquetes react-native-polyfill-globals y @babel/plugin-proposal-async-generator-functions.

Para utilizar collection.watch():

  1. Instalar las dependencias.

    npm install react-native-polyfill-globals text-encoding
    npm install --save-dev @babel/plugin-proposal-async-generator-functions
  2. Importa polyfills en un ámbito superior al lugar donde necesitas usarlos. Por ejemplo, en index.js.

    import { polyfill as polyfillReadableStream } from "react-native-polyfill-globals/src/readable-stream";
    import { polyfill as polyfillEncoding } from "react-native-polyfill-globals/src/encoding";
    import { polyfill as polyfillFetch } from "react-native-polyfill-globals/src/fetch";
    polyfillReadableStream();
    polyfillEncoding();
    polyfillFetch();

Importante

Serverless Limitations

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.

With the @realm/react package, make sure you have configured user authentication for your app.

Para supervisar todos los cambios en una colección, llame a collection.watch() sin argumentos. Esta llamada debe estar encapsulada por un UserProvider con un usuario autenticado.

import React, {useEffect} from 'react';
import Realm from 'realm';
import {useUser, useApp, AppProvider, UserProvider} from '@realm/react';
function AppWrapper() {
return (
<AppProvider id={APP_ID}>
<UserProvider fallback={<LogIn />}>
<NotificationSetter />
</UserProvider>
</AppProvider>
);
}
function NotificationSetter() {
// Get currently logged in user
const user = useUser();
const watchForAllChanges = async (
plants,
) => {
// Watch for changes to the plants collection
for await (const change of plants.watch()) {
switch (change.operationType) {
case 'insert': {
const {documentKey, fullDocument} = change;
// ... do something with the change information.
break;
}
case 'update': {
const {documentKey, fullDocument} = change;
// ... do something with the change information.
break;
}
case 'replace': {
const {documentKey, fullDocument} = change;
// ... do something with the change information.
break;
}
case 'delete': {
const {documentKey} = change;
// ... do something with the change information.
break;
}
}
}
};
useEffect(() => {
const plants = user
.mongoClient('mongodb-atlas')
.db('example')
.collection('plants');
// Set up notifications
watchForAllChanges(plants);
}, [user, watchForAllChanges]);
// ... rest of component
}
import React, {useEffect} from 'react';
import Realm from 'realm';
import {useUser, useApp, AppProvider, UserProvider} from '@realm/react';
function AppWrapper() {
return (
<AppProvider id={APP_ID}>
<UserProvider fallback={<LogIn />}>
<NotificationSetter />
</UserProvider>
</AppProvider>
);
}
function NotificationSetter() {
// Get currently logged in user
const user = useUser();
const watchForAllChanges = async (
plants: Realm.Services.MongoDB.MongoDBCollection<Plant>,
) => {
// Watch for changes to the plants collection
for await (const change of plants.watch()) {
switch (change.operationType) {
case 'insert': {
const {documentKey, fullDocument} = change;
// ... do something with the change information.
break;
}
case 'update': {
const {documentKey, fullDocument} = change;
// ... do something with the change information.
break;
}
case 'replace': {
const {documentKey, fullDocument} = change;
// ... do something with the change information.
break;
}
case 'delete': {
const {documentKey} = change;
// ... do something with the change information.
break;
}
}
}
};
useEffect(() => {
const plants = user!
.mongoClient('mongodb-atlas')
.db('example')
.collection<Plant>('plants');
// Set up notifications
watchForAllChanges(plants);
}, [user, watchForAllChanges]);
// ... rest of component
}

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 procesan todos los documentos de una colección a través de una serie de etapas denominadas pipeline de agregación. La agregación te permite filtrar y transformar documentos, recopilar datos resumidos sobre grupos de documentos relacionados y otras operaciones complejas de datos.

To execute an aggregation pipeline, pass an array of aggregation stages to collection.aggregate(). Aggregation operations return the result set of the last stage in the pipeline.

The following snippet groups all documents in the plants collection by their type value and aggregates a count of the number of each type:

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

Puedes usar la etapa $match para filtrar documentos según la sintaxis de queryestá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" }
]

You can use the $group stage to aggregate summary data for one or more documents. MongoDB groups documents based on the expression defined in the _id field of the $group stage. You can reference a specific document field by prefixing the field name with a $.

{
"$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 los resultados puedes utilizar consultas de agregación por rangos con los operadores $match, $sort, y $limit. Para obtener más información sobre cómo paginar documentos, consulta Uso de consultas por rango en la documentación de MongoDB Server.

Ejemplo

The following example paginates through a collection of documents in ascending order.

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

  • Incluya de forma explícita campos con un valor de 1. Esto tiene el efecto secundario de excluir, de forma implícita, todos los campos no especificados.

  • Implicitly exclude fields with a value of 0. This has the side-effect of implicitly including all unspecified fields.

Estos dos métodos de proyección son mutuamente excluyentes: si incluyes explícitamente campos, no puedes excluir explícitamente campos y viceversa.

Nota

The _id field is a special case: it is always included in every query unless explicitly specified otherwise. For this reason, you can exclude the _id field with a 0 value while simultaneously including other fields, like _partition, with a 1. Only the special case of exclusion of the _id field allows both exclusion and inclusion in one $project stage.

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

Ejemplo

The following $project stage omits the _id field, includes the name field, and creates a new field named storeNumber. The storeNumber is generated using two aggregation operators:

  1. $split separates the _partition value into two string segments surrounding the space character. For example, the value "Store 42" split in this way returns an array with two elements: "Store" and "42".

  2. $arrayElemAt selects a specific element from an array based on the second argument. In this case, the value 1 selects the second element from the array generated by the $split operator since arrays index from 0. For example, the value ["Store", "42"] passed to this operation would return a value of "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" }
]

Puedes utilizar la etapa $addFields para añadir nuevos campos con valores calculados utilizando operadores de agregación.

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

Nota

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

Ejemplo

The following $addFields stage creates a new field named storeNumber where the value is the output of two aggregate operators that transform the value of the _partition field.

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

You can use the $unwind stage to transform a single document containing an array into multiple documents containing individual values from that array. When you unwind an array field, MongoDB copies each document once for each element of the array field but replaces the array value with the array element in each copy.

{
$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. Use $group stage with $addToSet to create new documents for each type with a new field colors that contains an array of all the the colors for that flower type that occur in the collection.

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

  3. Use $sort stage to sort the results in alphabetical order.

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