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

Acceso a datos usando un cursor

En esta guía, puedes aprender cómo utilizar el controlador Rust para acceder a los datos devueltos de una operación de lectura o agregación mediante un cursor. Un cursor es un mecanismo que te permite iterar a través de varios documentos manteniendo solo un subconjunto de ellos en la memoria en un momento dado.

El conductor ofrece la Cursor tipo para recuperar documentos de un cursor. Por ejemplo, cuando ejecuta una operación de búsqueda que puede devolver varios documentos, el controlador retorna una instancia de Cursor desde la cual puedes acceder a los documentos coincidentes.

Después de ejecutar una operación de lectura o agregación, la instancia Cursor que se devuelve contiene el primer lote de resultados de la operación. A medida que se itera a través del cursor, el servidor devuelve más resultados individuales. Si hay más documentos coincidentes después de que llegues al final de un lote de resultados, la instancia Cursor recupera el siguiente lote de documentos hasta que se devuelvan todos los resultados.

Esta guía incluye las siguientes secciones:

  • Datos de muestra para ejemplos presenta los datos de muestra que usan los ejemplos de cursor.

  • Recuperar documentos individualmente describe cómo usar la iteración o un flujo para acceder a los resultados uno a la vez

  • Recuperar documentos como un arreglo describe cómo acceder a todos los resultados como un solo arreglo recopilando los resultados del cursor devueltos

  • Recuperar lotes de documentos sin procesar describe cómo usar la API del cursor de lotes sin procesar para el procesamiento de documentos sin copia con acceso directo a datos BSON

  • Especificar el comportamiento del cursor describe cómo configurar el cursor que un método devuelve

  • Información adicional proporciona enlaces a recursos y documentación de la API para los tipos y métodos mencionados en esta guía

Los ejemplos en esta guía utilizan los siguientes datos almacenados en una estructura:

let docs = vec! [
Fruit {
name: "strawberry".to_string(),
color: "red".to_string()
},
Fruit {
name: "banana".to_string(),
color: "yellow".to_string()
},
Fruit {
name: "pomegranate".to_string(),
color: "red".to_string()
},
Fruit {
name: "pineapple".to_string(),
color: "yellow".to_string()
}
];

El controlador proporciona los siguientes patrones de acceso para iterar a través de los documentos devueltos por una instancia de Cursor:

  • Patrón incorporado: avanza el cursor, luego recupera y deserializa el documento actual

  • Patrón de implementación de Stream: iterar sobre el cursor y llamar a los métodos proporcionados por Stream para procesar uno o varios documentos

Las siguientes secciones describen estos patrones de acceso y los métodos correspondientes con más detalle.

Puedes utilizar el patrón de acceso integrado del driver para recuperar y procesar documentos uno por uno.

El tipo Cursor incluye los métodos advance() y deserialize_current() para iterar a través de un cursor y acceder a los documentos individualmente.

El método advance() mueve el cursor hacia adelante y envía una solicitud a la base de datos para obtener más resultados cuando el búfer local se agota, lo que ocurre cuando el cursor llega al final de un lote de resultados. Cada vez que el cursor alcanza el final de un lote de resultados, solicita el siguiente lote. El cursor está agotado cuando ya no tiene más documentos coincidentes para devolver y ya no puede utilizarse. El método advance() devuelve un resultado true si se devuelven correctamente nuevos resultados y un resultado false si el cursor está cerrado.

El método deserialize_current() devuelve una referencia al resultado actual en el cursor y deserializa el resultado en el tipo asociado con el cursor. A menos que especifiques un tipo, el método utiliza el mismo tipo con el que tu colección está parametrizada.

Importante

Solo se puede llamar al método deserialize_current() si el método advance() devuelve un resultado true. El controlador genera un error si se llama a deserialize_current() en el cursor sin un resultado true o sin haber llamado previamente a advance().

El siguiente ejemplo muestra cómo implementar este patrón de acceso para iterar a través de los resultados de una operación find en la colección fruits:

let mut cursor = my_coll.find(doc! { "color": "red" }).await?;
while cursor.advance().await? {
println!("{:?}", cursor.deserialize_current()?);
}
Fruit { name: "strawberry", color: "red" }
Fruit { name: "pomegranate", color: "red" }

Puedes acceder a los resultados del cursor como un stream para recuperar documentos individuales o recopilar varios documentos a la vez.

El tipo Cursor implementa la característica Stream, por lo que puedes iterar a través de un cursor como un flujo. Puedes usar este patrón para ayudarte a escribir código más conciso que con el patrón incorporado, porque el rasgo de extensión Stream StreamExt ofrece numerosas funciones para combinar operaciones y consolidar código.

Puedes utilizar los siguientes métodos para emplear el patrón de flujo:

  • next()avanza el cursor al siguiente resultado y devuelve un tipo Option<Result<T>>

  • try_next()Avanza el cursor al siguiente resultado y devuelve un tipo Result<Option<T>>

Importante

Importaciones requeridas para Métodos de patrón de flujo

Para usar el método next(), debe importar el atributo StreamExt. Para usar el método try_next(), debe importar el atributo TryStreamExt.

El siguiente ejemplo muestra cómo implementar los dos métodos stream para iterar a través de los resultados de las operaciones find en la colección fruits:

let mut cursor = my_coll.find(doc! { "color": "red" }).await?;
println!("Output from next() iteration:");
while let Some(doc) = cursor.next().await {
println!("{:?}", doc?);
}
println!();
let mut cursor = my_coll.find(doc! { "color": "yellow" }).await?;
println!("Output from try_next() iteration:");
while let Some(doc) = cursor.try_next().await? {
println!("{:?}", doc);
}
Output from next() iteration:
Fruit { name: "strawberry", color: "red" }
Fruit { name: "pomegranate", color: "red" }
Output from try_next() iteration:
Fruit { name: "banana", color: "yellow" }
Fruit { name: "pineapple", color: "yellow" }

Debido a que el Cursor tipo implementa el rasgo Stream, puedes recolectar los resultados de un cursor en un arreglo.

Puedes usar los siguientes métodos para recuperar documentos como un arreglo:

  • collect()recopila los resultados de un cursor en un tipo Vec<Result<T>>

  • try_collect()recopila los resultados de un cursor en un tipo Result<Vec<T>>

Nota

Para usar el método collect(), debe importar el atributo StreamExt. Para usar el método try_collect(), debe importar el atributo TryStreamExt.

let cursor = my_coll.find(doc! { "color": "red" }).await?;
println!("Output from collect():");
let v: Vec<Result<Fruit>> = cursor.collect().await;
println!("{:?}", v);
println!();
let cursor = my_coll.find(doc! { "color": "yellow" }).await?;
println!("Output from try_collect():");
let v: Vec<Fruit> = cursor.try_collect().await?;
println!("{:?}", v);
Output from collect():
[Ok(Fruit { name: "strawberry", color: "red" }), Ok(Fruit { name: "pomegranate", color: "red" })]
Output from try_collect():
[Fruit { name: "banana", color: "yellow" }, Fruit { name: "pineapple", color: "yellow" }]

Advertencia

Evita superar los límites de memoria de la aplicación

Evita convertir grandes conjuntos de resultados en arreglos. Si el arreglo supera el tamaño de la memoria disponible de la aplicación, la aplicación podría fallar. Si espera un conjunto de resultados grande, recupere documentos del cursor individualmente. Para aprender cómo iterar a través del cursor, consulta la sección Recuperar documentos individualmente de esta guía.

Puede llamar al método batch() en operaciones que devuelven cursor, como find(), para devolver un RawBatchCursor. Esto le permite iterar sobre lotes de documentos BSON sin procesar devueltos por el servidor, en lugar de valores deserializados individuales. Este módulo proporciona un método de alto rendimiento para procesar documentos cuando necesita acceso directo a los lotes de respuesta del servidor. Utilice el modo de lote sin procesar para aplicaciones de cursor sensibles al rendimiento con alto rendimiento.

Para usar la API de cursores de lotes sin procesar, llame al método batch() en una operación que devuelva un cursor para devolver un RawBatchCursor en lugar del Cursor habitual. De esta forma, podrá iterar por lotes y acceder a documentos individuales dentro de cada uno.

El siguiente ejemplo muestra cómo utilizar el cursor de lote sin procesar para procesar documentos:

let mut cursor = my_coll.find(doc! { "color": "red" }).batch().await?;
while let Some(batch) = cursor.next().await {
let batch = batch?;
let doc_slices = batch.doc_slices()?;
let count = doc_slices.into_iter().count();
println!("Processing batch with {} documents", count);
for doc_result in batch.doc_slices()? {
let doc = doc_result?;
if let mongodb::bson::RawBsonRef::Document(raw_doc) = doc {
println!("Raw document size: {} bytes", raw_doc.as_bytes().len());
}
}
}
Processing batch with 4 documents
Raw document size: 58 bytes
Raw document size: 59 bytes
Raw document size: 58 bytes
Raw document size: 59 bytes

Para obtener más información sobre la API de cursor de lotes sin procesar, consulte el raw_batch_cursor página en la documentación de la API.

Para modificar el cursor que devuelve una operación, encadene los métodos del generador de opciones al método que devuelve la instancia Cursor. Por ejemplo, puede encadenar los métodos del generador de opciones relacionados con el cursor al método find().

Nota

Opciones de configuración

Puedes configurar los campos de FindOptions encadenando métodos del generador de opciones directamente a la llamada del método find(). Si está utilizando una versión anterior del controlador, debe construir una instancia de FindOptions encadenando métodos del generador de opciones al método builder(). Luego, pasa tu instancia de FindOptions como parámetro a find().

La siguiente tabla describe las opciones relacionadas con el cursor que puedes establecer llamando a su método generador correspondiente:

Configuración
Descripción

batch_size

Specifies the maximum number of documents the server returns per cursor batch. This option sets the number of documents the cursor keeps in memory rather than the number of documents the cursor returns.

Type: u32
Default: 101 documents initially, 16 MB maximum for subsequent batches

cursor_type

Specifies the type of cursor to return. You can set this option to produce a tailable cursor. To learn more about tailable cursors, see Tailable Cursors in the Server manual.

Type: CursorType
Default: CursorType::NonTailable

no_cursor_timeout

Specifies whether the server closes the cursor after a period of inactivity.

IMPORTANT: Because the Cursor type implements the Drop trait, the server closes a cursor when it goes out of scope. The server runs an asynchronous killCursors command to close the cursor. See killCursors in the Server manual to learn more.
Type: bool
Default: false

El siguiente código muestra cómo especificar la configuración relacionada con el cursor encadenando métodos de construcción de opciones al método find():

let mut cursor = my_coll.find(doc! { "color": "red" })
.batch_size(5)
.cursor_type(CursorType::Tailable)
.no_cursor_timeout(true)
.await?;

Para obtener más información sobre las operaciones de esta guía, consulte la siguiente documentación:

Para obtener más información sobre la conversión entre tipos de Rust y BSON, consulte la guía sobre modelado y serialización de datos.

Para obtener más información sobre los métodos y tipos mencionados en esta guía, vea la siguiente documentación de la API:

Volver

Especifica un query

En esta página