Menu Docs

Acessar dados de um cursor

As operações de leitura que retornam vários documentos não retornam imediatamente todos os valores correspondentes à query. Como uma query pode potencialmente corresponder a conjuntos muito grandes de documentos, essas operações retornam um objeto chamado cursor, que faz referência a documentos identificados pela query. Um cursor obtém documentos em lotes para reduzir o consumo de memória e o uso da largura de banda da rede. Os cursores são altamente configuráveis e oferecem vários paradigmas de interação para diferentes casos de uso.

As seguintes funções retornam cursores diretamente:

  • Collection.find()

  • Collection.aggregate()

  • Collection.listIndexes()

  • Collection.listSearchIndexes()

  • Db.aggregate()

  • Db.listCollections()

Outros métodos, como Collection.findOne() e Collection.watch() use cursores internamente e retorne os resultados das operações em vez de um cursor.

Você pode usar vários paradigmas de cursor diferentes para acessar dados. A maioria deles permite acessar os resultados da query um documento de cada vez, abstraindo a lógica de rede e de cache. No entanto, como os casos de uso são diferentes, outros paradigmas oferecem padrões de acesso diferentes, como a extração de todos os documentos correspondentes para uma coleção na memória do processo.

Aviso

Não combine diferentes paradigmas de cursor em um único cursor. Operações como hasNext() e toArray() modificam previsivelmente o cursor original. Se você misturar essas chamadas em um único cursor, poderá receber resultados inesperados.

Aviso

Como as chamadas assíncronas modificam diretamente o cursor, a execução simultânea de chamadas assíncronas em um único cursor também pode causar comportamento indefinido. Aguarde sempre que a operação assíncrona anterior seja concluída antes de executar outra.

Observação

Quando você atinge o último resultado através da iteração ou através de uma busca única, o cursor se esgota, o que significa que ele deixa de responder aos métodos que acessam os resultados.

Os cursores implementam a interface AsyncIterator, que permite usar cursores em loops for await...of:

const cursor = myColl.find({});
console.log("async");
for await (const doc of cursor) {
console.log(doc);
}

Você pode utilizar o método hasNext() para verificar se um cursor pode recuperar mais dados e, em seguida, utilizar o método next() para recuperar o elemento subsequente do cursor:

const cursor = myColl.find({});
while (await cursor.hasNext()) {
console.log(await cursor.next());
}

Para casos de uso que exigem que todos os documentos correspondidos por uma query sejam mantidos na memória ao mesmo tempo, use o método toArray(). Observe que um grande número de documentos correspondentes pode causar problemas de desempenho ou falhas se a operação exceder as restrições de memória. Considere usar a sintaxe for await...of para iterar os resultados em vez de retornar todos os documentos de uma só vez.

const cursor = myColl.find({});
const allValues = await cursor.toArray();

Os cursores expõem o método stream() para convertê-los em fluxos legíveis de nó. Esses fluxos operam no Modo de Objeto, que passa objetos JavaScript em vez de Buffers ou Strings pelo pipeline.

const cursor = myColl.find({});
cursor.stream().on("data", doc => console.log(doc));

Como fluxos legíveis, os cursores também são compatíveis com os eventos close, data, end e readable da API de eventos:

const cursor = myColl.find({});
// the "data" event is fired once per document
cursor.on("data", data => console.log(data));

Para redefinir um cursor para sua posição inicial no conjunto de documentos retornados, use 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);

Os cursores consomem memória e recursos de rede tanto no aplicativo cliente quanto na instância conectada do MongoDB. Use close() para liberar os recursos de um cursor no aplicativo cliente e no servidor MongoDB:

await cursor.close();

Você pode cancelar as operações do cursor usando um sinal de cancelamento. Isso pode ajudá-lo a gerenciar seus recursos liberando memória e recursos de rede usados pelo cursor se não forem mais necessários.

Observação

Este recurso é experimental. Abortar um sinal fecha uma conexão, o que pode causar o restabelecimento desnecessário da conexão.

Você pode passar o comando signal para os seguintes métodos:

  • collection.find()

  • collection.findOne()

  • collection.aggregate()

  • collection.countDocuments()

  • db.listCollections()

  • db.command()

Para usar um sinal de cancelamento, crie uma instância AbortController e extraia o signal do controlador. Neste exemplo de código , o processo escuta um SIGINT (Ctrl+C) para acionar o método abort(). Você pode passar a opção signal para o método find() para abortar a operação do cursor se o sinal for acionado, conforme mostrado no exemplo a seguir:

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);
}
}