Overview
Las operaciones de lectura que devuelven varios documentos no devuelven inmediatamente todos los valores que coinciden con la query. Debido a que una query puede potencialmente coincidir con conjuntos muy grandes de documentos, estas operaciones devuelven un objeto llamado cursor, que hace referencia a los documentos identificados por la query. Un cursor obtiene documentos en lotes para reducir tanto el consumo de memoria como el uso del ancho de banda de la red. Los cursores se pueden configurar ampliamente y ofrecen múltiples paradigmas de interacción para diferentes casos de uso.
Las siguientes funciones devuelven directamente los cursores:
Collection.find()Collection.aggregate()Collection.listIndexes()Collection.listSearchIndexes()Db.aggregate()Db.listCollections()
Otros métodos como colección.findOne() y colección.watch() utilizan cursores internamente y devuelven los resultados de las operaciones en lugar de un cursor.
Paradigmas del cursor
Puedes usar varios paradigmas de cursor distintos para acceder a los datos. La mayoría de los paradigmas de cursor permiten acceder a los resultados de la query un documento a la vez, abstraiendo la lógica de red y almacenamiento en caché. Sin embargo, como los casos de uso pueden variar, otros paradigmas ofrecen diferentes patrones de acceso, como extraer todos los documentos que coinciden a una colección en la memoria del proceso.
Advertencia
No combines diferentes paradigmas de cursor en un solo cursor. Operaciones como hasNext() y toArray() modifican de manera predecible el cursor original. Si mezclas estas llamadas en un único cursor, es posible que obtengas resultados inesperados.
Advertencia
Dado que las llamadas asincrónicas modifican directamente el cursor, ejecutarlas simultáneamente en un mismo cursor también puede causar un comportamiento indefinido. Espere siempre a que la operación asincrónica anterior se complete antes de ejecutar otra.
Nota
Cuando se alcanza el último resultado mediante iteración o mediante una obtención integral, el cursor está agotado, lo que significa que deja de responder a los métodos que acceden a los resultados.
Iteración asincrónica
los cursores implementan el AsyncIterator interfaz, que permite utilizar cursores en bucles for await...of:
const cursor = myColl.find({}); console.log("async"); for await (const doc of cursor) { console.log(doc); }
Iteración manual
Puede usar el método hasNext() para verificar si un cursor puede recuperar más datos y luego usar el método next() para recuperar el elemento siguiente del cursor:
const cursor = myColl.find({}); while (await cursor.hasNext()) { console.log(await cursor.next()); }
Devolver un arreglo de todos los documentos
Para casos de uso que requieren que todos los documentos coincidentes con una query permanezcan en la memoria al mismo tiempo, utilice el método toArray(). Ten en cuenta que un gran número de documentos encontrados puede causar problemas de rendimiento o fallos si la operación supera las restricciones de memoria. Considera usar la sintaxis for await...of para iterar por los resultados en lugar de devolver todos los documentos a la vez.
const cursor = myColl.find({}); const allValues = await cursor.toArray();
API de streaming
Los cursores exponen el método stream() para convertirlos en flujos legibles por nodos. Estos flujos operan en el Modo de Objeto, que pasa objetos de JavaScript en lugar de búferes o cadenas a través de la pipeline.
const cursor = myColl.find({}); cursor.stream().on("data", doc => console.log(doc));
API de eventos
Como secuencias legibles, los cursores también admiten los eventos close, data, end y readable de la API de eventos:
const cursor = myColl.find({}); // the "data" event is fired once per document cursor.on("data", data => console.log(data));
Métodos de utilidad del cursor
Rebobinar
Para restablecer un cursor a su posición inicial en el conjunto de documentos devueltos, utilice rewind().
const cursor = myColl.find({}); const firstResult = await cursor.toArray(); console.log("First count: " + firstResult.length); await cursor.rewind(); const secondResult = await cursor.toArray(); console.log("Second count: " + secondResult.length);
Cerrar
Los cursores consumen memoria y recursos de red tanto en la aplicación cliente como en la instancia conectada de MongoDB. Utilice close() para liberar los recursos de un cursor tanto en la aplicación cliente como en el MongoDB Server, como se muestra en el siguiente ejemplo:
await cursor.close();
Recomendamos cerrar manualmente cualquier cursor no agotado que tu aplicación ya no utilice para prevenir fugas de recursos.
Tip
Gestión explícita de recursos
El controlador de Nodo.js admite de forma nativa la gestión explícita de recursos para MongoClient, ClientSession, ChangeStreams y cursores. Esta característica es experimental y está sujeta a cambios. Para aprender a utilizar la gestión explícita de recursos, consulta las Notas de versión v6.9.
Abortar
Puedes cancelar operaciones de cursor utilizando una señal de aborto. Esto te puede ayudar a gestionar tus recursos liberando memoria y recursos de red que utiliza el cursor si ya no se necesitan.
Nota
Esta funcionalidad es experimental. Abortar una señal cierra una conexión, lo que podría causar la reanudación innecesaria de la conexión.
Puedes pasar el comando signal a los siguientes métodos:
collection.find()collection.findOne()collection.aggregate()collection.countDocuments()db.listCollections()db.command()
Para utilizar una señal de aborto, crea una instancia de AbortController y extrae el signal del controlador. En este ejemplo de código, el proceso escucha una SIGINT (Ctrl+C) para activar el método abort(). Puedes pasar la opción signal al método find() para abortar la operación del cursor si la señal se activa, como se muestra en el siguiente ejemplo:
const controller = new AbortController(); const { signal } = controller; process.on('SIGINT', () => controller.abort(new Error('^C pressed'))); try { const cursor = myColl.find({}, { signal }); for await (const doc of cursor) { console.log(doc); } } catch (error) { if (error === signal.reason) { console.error('Operation aborted:', error); } else { console.error('Unexpected error:', error); } }