Acessar dados usando um cursor
Nesta página
Visão geral
Neste guia, você aprenderá a usar o driver Rust para acessar os dados retornados de uma operação de leitura ou agregação usando um cursor . Um cursor é um mecanismo que permite iterar vários documentos enquanto mantém apenas um subconjunto deles na memória em determinado momento.
O driver oferece o tipo Cursor
para recuperar documentos de um cursor. Por exemplo, ao executar uma operação de localizar que pode retornar vários documentos, o driver retorna uma instância do Cursor
da qual você pode acessar os documentos correspondentes.
Após executar uma operação de leitura ou agregação, a instância do Cursor
retornada contém o primeiro lote de resultados da operação. À medida que você itera pelo cursor, o servidor retorna mais resultados individuais. Se houver mais documentos correspondentes depois que você chegar ao final de um lote de resultados, a instância Cursor
buscará o próximo lote de documentos até que todos os resultados sejam retornados.
Este guia inclui as seguintes seções:
Amostra de dados para exemplos apresenta os dados de amostra que são usados pelos exemplos do cursor
Recuperar documentos Descreve individualmente como usar a iteração ou um fluxo para acessar os resultados um de cada vez
Recuperar documentos como array descreve como acessar todos os resultados como um único array coletando os resultados do cursor retornado
Especificar o Comportamento do Cursor descreve como configurar o cursor que um método retorna
Informações adicionais fornecem links para recursos e documentação da API para os tipos e métodos mencionados neste guia
Dados de amostra para exemplos
Os exemplos deste guia usam os seguintes dados armazenados em uma estrutura:
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() } ];
Recuperar documentos individualmente
O driver fornece os seguintes padrões de acesso para iterar por meio de documentos retornados por uma instância Cursor
:
Padrão integrado: avance o cursor, depois recupere e desserialize o documento atual
Padrão de implementação de fluxo: iterar sobre o cursor e chamar os métodos fornecidos pelo
Stream
para processar um ou vários documentos
As seções a seguir descrevem esses padrões de acesso e métodos correspondentes em mais detalhes.
Padrão integrado
Você pode usar o padrão de acesso integrado do driver para recuperar e processar documentos um a um.
O tipo Cursor
inclui os métodos advance()
e deserialize_current()
para iterar por meio de um cursor e acessar documentos individualmente.
O método advance()
move o cursor para a frente e envia uma solicitação ao reconhecimento de data center para mais resultados quando o buffer local se esgota, o que ocorre quando o cursor atinge o final de um lote de resultados. Cada vez que o cursor chega ao final de um lote de resultados, ele solicita o próximo lote. O cursor fica esgotado quando não tem mais documentos correspondentes para retornar e não pode mais ser usado. O método advance()
retorna um resultado true
se os novos resultados forem retornados com êxito e um resultado false
se o cursor estiver fechado.
O método deserialize_current()
retorna uma referência ao resultado atual no cursor e desserializa o resultado no tipo associado ao cursor. A menos que você especifique um tipo, o método usa o mesmo tipo com o qual sua coleção é parametrizada.
Importante
Você pode chamar o método deserialize_current()
somente se o método advance()
retornar um resultado true
. O driver gera um erro se você chamar deserialize_current()
no cursor sem um resultado true
ou sem chamar anteriormente advance()
.
O exemplo a seguir mostra como implementar esse padrão de acesso para iterar os resultados de uma operação de localizar na coleção 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" }
Padrão de implementação de fluxo
Você pode acessar os resultados do cursor como um fluxo para recuperar documentos individuais ou coletar vários documentos de uma só vez.
O tipo Cursor
implementa a Stream
, para que você possa iterar por meio de um cursor como um fluxo. Você pode usar esse padrão para escrever um código mais conciso do que com o padrão integrado, pois a extensão Stream
StreamExt
fornece inúmeras funções para combinar operações e confirmar código.
Você pode usar os seguintes métodos para usar o padrão de fluxo:
next()
: avança o cursor para o próximo resultado e retorna um tipoOption<Result<T>>
try_next()
: avança o cursor para o próximo resultado e retorna um tipoResult<Option<T>>
Importante
Importações necessárias para métodos de padrão de stream
Para usar o método next()
, você deve importar o traço StreamExt
. Para usar o método try_next()
, você deve importar o traço TryStreamExt
.
O exemplo a seguir mostra como implementar os dois métodos de fluxo para iterar os resultados das operações de localização na collection 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" }
Recuperar documentos como um array
Como o tipo Cursor
implementa a Stream
, você pode coletar os resultados de um cursor em uma array.
Você pode usar os seguintes métodos para recuperar documentos como um array:
collect()
: coleta resultados de um cursor em um tipoVec<Result<T>>
try_collect()
: coleta resultados de um cursor em um tipoResult<Vec<T>>
Observação
Para usar o método collect()
, você deve importar o traço StreamExt
. Para usar o método try_collect()
, você deve importar o traço 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" }]
Aviso
Evite exceder os limites de memória do aplicativo
Evite converter grandes conjuntos de resultados em arrays. Se a array exceder o tamanho da memória disponível do aplicação , seu aplicação poderá falhar. Se você espera um conjunto de resultados grande, recupere os documentos do cursor individualmente. Para saber como fazer a iteração por meio do cursor, consulte a seção Recuperar documentos individualmente deste guia.
Especificar comportamento do cursor
Para modificar o cursor que uma operação retorna, encadeie os métodos do construtor de opções ao método que retorna a instância Cursor
. Por exemplo, é possível encadear métodos de construtor de opção relacionados ao cursor ao método find()
.
Observação
Opções de configuração
Você pode definir FindOptions
campos encadeando métodos de construtor de opções diretamente à chamada de método find()
. Se você estiver utilizando uma versão anterior do driver, você deverá construir uma instância do FindOptions
encadeando métodos de construtor de opção ao método builder()
. Em seguida, passe sua instância FindOptions
como parâmetro para find()
.
A tabela a seguir descreve as opções relacionadas ao cursor que você pode definir chamando o método de construtor correspondente:
Contexto | Descrição |
---|---|
| 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 |
| 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 |
| 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 |
O código a seguir mostra como especificar configurações relacionadas ao cursor encadeando métodos de construtor de opção ao método find()
:
let mut cursor = my_coll.find(doc! { "color": "red" }) .batch_size(5) .cursor_type(CursorType::Tailable) .no_cursor_timeout(true) .await?;
Informações adicionais
Para saber mais sobre as operações neste guia, consulte a seguinte documentação:
Para saber mais sobre a conversão entre tipos de Rust e BSON, consulte o guia sobre modelagem de dados e serialização.
Documentação da API
Para saber mais sobre os métodos e tipos mencionados neste guia, consulte a documentação da API abaixo:
próximo() no
StreamExt
traçotry_next() no
TryStreamExt
traçocollection() no
StreamExt
traçotry_collect() no
TryStreamExt
traço