Obrigado por me levar a escrever uma explicação mais clara. Aqui está um exemplo mais completo com meus comentários. Houve alguns bugs e inconsistências que eu limpei. A próxima versão de documentos usará isso.
Meteor.publish
é bastante flexível. Não se limita a publicar coleções existentes do MongoDB para o cliente:podemos publicar o que quisermos. Especificamente, Meteor.publish
define um conjunto de documentos que um cliente pode assinar. Cada documento pertence a algum nome de coleção (uma string), possui um _id
exclusivo campo e, em seguida, tem algum conjunto de atributos JSON. À medida que os documentos no conjunto mudam, o servidor enviará as alterações para cada cliente inscrito, mantendo o cliente atualizado. Vamos definir um conjunto de documentos aqui, chamado
"counts-by-room"
, que contém um único documento em uma coleção chamada "counts"
. O documento terá dois campos:um roomId
com o ID de uma sala e count
:o número total de mensagens naquela sala. Não existe uma coleção real do MongoDB chamada counts
. Este é apenas o nome da coleção que nosso servidor Meteor enviará para o cliente e armazenará em um client-side coleção chamada counts
. Para fazer isso, nossa função de publicação usa um
roomId
parâmetro que virá do cliente, e observa uma consulta de todas as Mensagens (definidas em outro lugar) naquela sala. Podemos usar o método observeChanges
mais eficiente forma de observar uma consulta aqui, pois não precisaremos do documento completo, apenas o conhecimento de que um novo foi adicionado ou removido. Sempre que uma nova mensagem é adicionada com o roomId
estamos interessados, nosso retorno de chamada incrementa a contagem interna e, em seguida, publica um novo documento para o cliente com esse total atualizado. E quando uma mensagem é removida, ela diminui a contagem e envia a atualização ao cliente. Quando chamamos
observeChanges
pela primeira vez , algum número de added
retornos de chamada serão executados imediatamente, para cada mensagem que já existe. Em seguida, as alterações futuras serão acionadas sempre que as mensagens forem adicionadas ou removidas. Nossa função de publicação também registra um
onStop
manipulador para limpar quando o cliente cancela a assinatura (manualmente ou na desconexão). Este manipulador remove os atributos do cliente e elimina o observeChanges
em execução . Uma função de publicação é executada sempre que um novo cliente se inscreve em
"counts-by-room"
, então cada cliente terá um observeChanges
correndo em seu nome. // server: publish the current size of a collection
Meteor.publish("counts-by-room", function (roomId) {
var self = this;
var count = 0;
var initializing = true;
var handle = Messages.find({room_id: roomId}).observeChanges({
added: function (doc, idx) {
count++;
if (!initializing)
self.changed("counts", roomId, {count: count}); // "counts" is the published collection name
},
removed: function (doc, idx) {
count--;
self.changed("counts", roomId, {count: count}); // same published collection, "counts"
}
// don't care about moved or changed
});
initializing = false;
// publish the initial count. `observeChanges` guaranteed not to return
// until the initial set of `added` callbacks have run, so the `count`
// variable is up to date.
self.added("counts", roomId, {count: count});
// and signal that the initial document set is now available on the client
self.ready();
// turn off observe when client unsubscribes
self.onStop(function () {
handle.stop();
});
});
Agora, no cliente, podemos tratar isso como uma assinatura típica do Meteor. Primeiro, precisamos de um
Mongo.Collection
que conterá nosso documento de contagens calculadas. Como o servidor está publicando em uma coleção chamada "counts"
, passamos "counts"
como o argumento para o Mongo.Collection
construtor. // client: declare collection to hold count object
Counts = new Mongo.Collection("counts");
Então podemos assinar. (Você pode se inscrever antes de declarar a coleção:o Meteor irá enfileirar as atualizações recebidas até que haja um lugar para colocá-las.) O nome da assinatura é
"counts-by-room"
, e leva um argumento:o ID da sala atual. Eu envolvi isso dentro de Deps.autorun
para que como Session.get('roomId')
alterações, o cliente cancelará automaticamente a contagem do quarto antigo e reassinará a contagem do novo quarto. // client: autosubscribe to the count for the current room
Tracker.autorun(function () {
Meteor.subscribe("counts-by-room", Session.get("roomId"));
});
Por fim, temos o documento em
Counts
e podemos usá-lo como qualquer outra coleção Mongo no cliente. Qualquer modelo que faça referência a esses dados será redesenhado automaticamente sempre que o servidor enviar uma nova contagem. // client: use the new collection
console.log("Current room has " + Counts.findOne().count + " messages.");