Documentação
Introdução
find() retorna um cursor: os documentos encontrados, prontos para serem ordenados, paginados,
projetados e lidos.
const page = people.find({ city: 'Recife' })
.sort({ age: -1, name: 1 })
.skip(20)
.limit(10)
.toArray();
Como um cursor funciona
Um cursor guarda referências aos documentos armazenados, não cópias. A busca, sort(), skip(),
limit(), length e ids() não copiam nada; um documento só é copiado quando você o lê com
next(), toArray(), first(), last(), forEach() ou for…of. Ler uma página de um milhão de
resultados copia uma página.
Os documentos armazenados nunca são alterados no lugar (uma atualização guarda uma nova versão),
então um cursor é um snapshot, um retrato consistente: ele continua mostrando os documentos como
eram quando o find() rodou, mesmo que sejam atualizados ou excluídos depois.
const cursor = people.find({ city: 'Recife' });
people.updateOne({ _id: 1 }, { $set: { age: 99 } });
cursor.toArray()[0].age; // 31: o snapshot
people.find({ _id: 1 }).first().age; // 99: um novo find enxerga a mudança
Leitura
| Membro | Retorna | Descrição |
|---|---|---|
toArray() |
object[] |
Cópias de todos os documentos, como objetos comuns |
for (const doc of cursor) |
object a cada vez |
Copia um de cada vez (pare antes com break e o restante nunca é copiado) |
forEach(fn) |
void |
fn(copy, index) para cada documento |
first() / last() |
object | null |
Cópia do primeiro / último documento |
ids() |
unknown[] |
O _id de cada documento, sem cópia nenhuma |
length |
number |
Quantidade de documentos |
hasNext() / next() / reset() |
Percorre os documentos um a um; next() lança No more item to the cursor no final |
for (const person of people.find({ age: { $gte: 18 } })) {
if (person.name === 'Davi') break; // os documentos depois do Davi nunca são copiados
}
const ids = people.find({ tags: { $in: ['dev'] } }).ids(); // [1]
const cursor = people.find({});
while (cursor.hasNext()) {
const doc = cursor.next(); // uma cópia envolvida como documento: doc.name, doc._data
}
cursor.reset(); // começa de novo
next() retorna um wrapper de documento (os campos são lidos como propriedades, e os dados ficam em
doc._data); os outros métodos de leitura retornam objetos comuns. Em ambos os casos, são cópias.
Ordenação
people.find({}).sort({ age: 1 }); // crescente
people.find({}).sort({ city: 1, age: -1 }); // por cidade, depois por idade decrescente
people.find({}).sort({ 'address.zip': 1 }); // caminhos aninhados
1 é crescente, -1 é decrescente; qualquer outro valor lança um erro
(Sort direction of "age" must be 1 or -1). sort() ordena no lugar e retorna o cursor. A ordenação
é estável: documentos considerados iguais mantêm a ordem de inserção.
Valores ausentes e null
Valores ausentes e null ficam por último nas duas direções, como numa planilha:
tasks.find({}).sort({ due: 1 }); // tarefas com data primeiro, depois as sem data
tasks.find({}).sort({ due: -1 }); // mais recentes primeiro, as sem data continuam no fim
tasks.find({}).sort({ due: 1 }, { nulls: 'first' }); // sem data primeiro
Defina o valor padrão de uma coleção com createCollection(name, schema, { nulls: 'first' }) ou
collection.setOptions({ nulls }); a opção do sort tem prioridade sobre ele. Antes da 1.6, eles
vinham primeiro na ordem crescente (a ordem do MongoDB); { nulls: 'first' } devolve essa ordem.
Tipos misturados
Valores de tipos diferentes são ordenados como no MongoDB: números, strings, objetos, arrays,
booleanos, datas (e depois ausentes / null, ou no início com nulls: 'first').
Texto de acordo com o idioma
Por padrão, as strings são comparadas por code point ('B' < 'a', 'é' > 'z'). Passe uma collation,
com as opções do Intl.Collator, para ordenar segundo as regras do idioma:
people.find({}).sort({ name: 1 }, { collation: { locale: 'pt-BR', sensitivity: 'base' } });
files.find({}).sort({ name: 1 }, { collation: { locale: 'en', numeric: true } }); // 'item 2' antes de 'item 10'
Paginação
const pageSize = 20;
const page = n => people.find({}).sort({ name: 1 }).skip(n * pageSize).limit(pageSize).toArray();
| Membro | Descrição |
|---|---|
skip(count) |
Descarta os primeiros count documentos (aplique depois do sort, como no MongoDB) |
limit(count) |
Mantém no máximo count; 0 significa sem limite |
Os dois exigem um inteiro não negativo. O total para um paginador é people.count(query) ou o
length do cursor antes do skip.
Projeção
Escolha os campos das cópias que você recebe:
people.find({}, { name: 1, age: 1 }); // só name, age e _id
people.find({}, { name: 1, _id: 0 }); // só name
people.find({}, { tags: 0 }); // tudo, menos tags
people.find({}).projection({ name: 1 }); // o mesmo que o segundo argumento
Inclusão (1) e exclusão (0) não podem ser misturadas, exceto para o _id; a projeção funciona
com campos de primeiro nível (Projection supports top level fields only). Ela se aplica às cópias:
os documentos armazenados mantêm todos os campos, e a ordenação pode usar campos que a projeção
esconde.
Resumo rápido
const c = people.find(query, projection);
c.sort({ field: 1 }, { nulls: 'last', collation: { locale: 'pt-BR' } });
c.skip(40).limit(20);
c.length; c.ids(); // sem cópias
c.toArray(); c.first(); c.last(); // cópias
for (const doc of c) {} c.forEach(fn); // cópias, uma de cada vez
c.hasNext(); c.next(); c.reset();