Docs Menu
Docs Home
/ /

Acceder a los datos mediante un cursor

En esta guía, aprenderá a usar el controlador de Rust para acceder a los datos devueltos por una operación de lectura o agregación mediante un cursor. Un cursor es un mecanismo que permite iterar a través de múltiples documentos manteniendo solo un subconjunto de ellos en memoria en un momento dado.

El conductor ofrece la Cursor Tipo para recuperar documentos de un cursor. Por ejemplo, al ejecutar una operación de búsqueda que puede devolver varios documentos, el controlador devuelve una instancia Cursor desde la que se puede acceder a los documentos coincidentes.

Tras ejecutar una operación de lectura o agregación, la instancia Cursor devuelta contiene el primer lote de resultados de la operación. A medida que se itera sobre el cursor, el servidor devuelve más resultados individuales. Si hay más documentos coincidentes después de llegar 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 se utilizan en los ejemplos del cursor

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

  • Recuperar documentos como una matriz describe cómo acceder a todos los resultados como una única matriz recopilando los resultados del cursor devueltos

  • 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 API para los tipos y métodos mencionados en esta guía.

Los ejemplos de 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 Cursor:

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

  • Patrón de implementación de flujo: itera sobre el cursor y llama 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.

Puede utilizar el patrón de acceso integrado del controlador 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 llega al final de un lote de resultados, solicita el siguiente. El cursor se agota cuando no tiene más documentos coincidentes que devolver y ya no se puede utilizar. El método advance() devuelve un resultado true si se devuelven nuevos resultados correctamente y un resultado false si se cierra el cursor.

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

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

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

El tipo Cursor implementa el rasgo Stream, lo que permite iterar sobre un cursor como un flujo. Este patrón puede ayudarte a escribir código más conciso que con el patrón integrado, ya que el rasgo de extensión Stream StreamExt proporciona numerosas funciones para combinar operaciones y consolidar código.

Puede utilizar los siguientes métodos para utilizar 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 patrones 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 de flujo para iterar a través de los resultados de las operaciones de búsqueda 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 tipo Cursor implementa el rasgo Stream, puede recopilar los resultados de un cursor en una matriz.

Puede utilizar los siguientes métodos para recuperar documentos como una matriz:

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

  • try_collect(): recopila 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

Evite exceder los límites de memoria de la aplicación

Evite convertir grandes conjuntos de resultados en matrices. Si la matriz excede el tamaño de la memoria disponible de la aplicación, esta podría bloquearse. Si espera un conjunto de resultados grande, recupere los documentos del cursor individualmente. Para aprender a iterar sobre el cursor, consulte la sección "Recuperar documentos individualmente" de esta guía.

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

Puede configurar los campos FindOptions encadenando los métodos del generador de opciones directamente a la llamada al método find(). Si utiliza una versión anterior del controlador, debe construir una instancia FindOptions encadenando los métodos del generador de opciones al método builder(). A continuación, pase la instancia FindOptions como parámetro a find().

La siguiente tabla describe las opciones relacionadas con el cursor que puede configurar llamando a su método de generación 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 configuraciones relacionadas con el cursor encadenando métodos de generació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, consulte la siguiente documentación de API:

Volver

Especifica un query

En esta página