Documentação

Introdução

As coleções avisam sobre cada mudança. Use eventos para salvar no localStorage, sincronizar com um servidor, registrar logs ou atualizar uma interface manualmente (para interfaces, as consultas vivas costumam ser mais simples).

const off = products.on('change', event => {
  console.log(event.type, event.ids);   // 'update' ['tea']
});
products.updateOne({ _id: 'tea' }, { $set: { price: 9 } });
off();   // para de ouvir

Tipos de evento

Evento Emitido por Conteúdo
insert insertOne, insertMany, upserts, inserções do bulkWrite { type, ids, documents }
update updateOne, updateMany, atualizações do bulkWrite { type, ids, documents, previous }
replace replaceOne { type, ids, documents, previous }
delete deleteOne, deleteMany { type, ids, documents }
change todos os anteriores o mesmo conteúdo; type diz qual foi

documents são cópias das novas versões e previous são cópias das versões anteriores a um update ou replace, na ordem de ids. Para delete, documents são os próprios documentos removidos (eles não estão mais na coleção).


Um evento por operação

insertMany, updateMany e deleteMany emitem um evento para a operação inteira, e o bulkWrite emite um por tipo, no final. Uma escrita que não muda nada (atualizar um campo com o valor que ele já tem, remover com um filtro que não corresponde a nada) não emite nada.


API

const off = products.on('update', listener);     // retorna uma função para cancelar a inscrição
products.once('insert', listener);                // apenas o próximo
products.off('update', listener);                 // remove um ouvinte
products.off('update');                           // remove todos os ouvintes desse tipo

Ouvintes não quebram escritas

Um ouvinte que lança um erro não desfaz nem interrompe a escrita, e os outros ouvintes continuam rodando; o erro é relançado de forma assíncrona para aparecer no console.


Cópias só quando alguém está ouvindo

As cópias em documents e previous só são feitas quando existe um ouvinte para aquele tipo ou para change. Sem ouvintes, uma escrita não paga nada pelos eventos.


Receitas

// persistir uma coleção no localStorage
const save = () => localStorage.setItem('tasks', JSON.stringify(tasks.find({}).toArray()));
tasks.on('change', save);
tasks.insertMany(JSON.parse(localStorage.getItem('tasks') ?? '[]'));

// enviar as mudanças para um servidor
tasks.on('change', ({ type, ids, documents }) => fetch('/api/tasks/sync', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ type, ids, documents })
}));

// um histórico de auditoria
const history = [];
users.on('update', ({ ids, documents, previous }) =>
  ids.forEach((id, i) => history.push({ id, before: previous[i], after: documents[i], at: Date.now() })));