Gracias por pedirme que escriba una explicación más clara. Aquí hay un ejemplo más completo con mis comentarios. Hubo algunos errores e inconsistencias que he limpiado. La próxima versión de documentos usará esto.
Meteor.publish
es bastante flexible. No se limita a publicar colecciones existentes de MongoDB para el cliente: podemos publicar todo lo que queramos. Específicamente, Meteor.publish
define un conjunto de documentos a los que un cliente puede suscribirse. Cada documento pertenece a algún nombre de colección (una cadena), tiene un campo único _id
y luego tiene algún conjunto de atributos JSON. A medida que cambian los documentos en el conjunto, el servidor enviará los cambios a cada cliente suscrito, manteniendo al cliente actualizado.
Vamos a definir un conjunto de documentos aquí, llamado "counts-by-room"
, que contiene un único documento en una colección llamada "counts"
. El documento tendrá dos campos: un roomId
con el ID de una habitación, y count
: el número total de mensajes en esa habitación. No hay una colección real de MongoDB llamada counts
. Este es solo el nombre de la colección que nuestro servidor Meteor enviará al cliente y que se almacenará en una colección del lado del cliente llamada counts
.
Para hacer esto, nuestra función de publicación toma un parámetro roomId
que vendrá del cliente, y observa una consulta de todos los mensajes (definidos en otra parte) en esa habitación. Podemos utilizar la forma más eficiente observeChanges
de observar aquí una consulta, ya que no necesitaremos el documento completo, solo el conocimiento de que se ha agregado o eliminado uno nuevo. Cada vez que se agrega un nuevo mensaje con el roomId
que nos interesa, nuestra devolución de llamada incrementa el recuento interno y luego publica un nuevo documento para el cliente con ese total actualizado. Y cuando se elimina un mensaje, disminuye el recuento y envía al cliente la actualización.
Cuando llamemos por primera vez al observeChanges
, se ejecutará un número de added
devoluciones de llamada de inmediato, por cada mensaje que ya exista. Luego, los cambios futuros se activarán cada vez que se agreguen o eliminen mensajes.
Nuestra función de publicación también registra un controlador onStop
para limpiar cuando el cliente cancela la suscripción (ya sea manualmente o al desconectarse). Este controlador elimina los atributos del cliente y elimina la ejecución observeChanges
.
Una función de publicación se ejecuta cada vez que un nuevo cliente se suscribe a "counts-by-room"
, por lo que cada cliente tendrá un observeChanges
ejecutándose en su nombre.
// 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();
});
});
Ahora, en el cliente, podemos tratar esto como una suscripción típica de Meteor. Primero, necesitamos un Mongo.Collection
que contendrá nuestro documento de cuentas calculadas. Como el servidor está publicando en una colección llamada "counts"
, pasamos "counts"
como el argumento al constructor Mongo.Collection
.
// client: declare collection to hold count object
Counts = new Mongo.Collection("counts");
Luego, podemos suscribirnos. (En realidad, puede suscribirse antes de declarar la recopilación: Meteor pondrá en cola las actualizaciones entrantes hasta que haya un lugar donde ubicarlas). El nombre de la suscripción es "counts-by-room"
y requiere un argumento: el ID de la habitación actual. Envolví esto dentro de Deps.autorun
para que como Session.get('roomId')
cambie, el cliente se dará de baja automáticamente del recuento de la habitación anterior y volverá a suscribirse al recuento de la nueva sala.
// client: autosubscribe to the count for the current room
Tracker.autorun(function() {
Meteor.subscribe("counts-by-room", Session.get("roomId"));
});
Por último, tenemos el documento en Counts
y podemos utilizarlo como cualquier otra colección Mongo en el cliente. Cualquier plantilla que haga referencia a estos datos se volverá a dibujar automáticamente cada vez que el servidor envíe un nuevo recuento.
// client: use the new collection
console.log("Current room has " + Counts.findOne().count + " messages.");
Borrar as bell! ¡Muchas gracias por tomarse el tiempo de aclarar esto para mí! –
Tenga en cuenta que 'self.flush();' dentro de 'added' empujará esa suscripción al cliente a medida que se rellena la colección. Imagine que tiene 1,000,000 de "Mensajes" en ese "room_id". Se le enviarán 1,000,000 de suscripciones desde el recuento 1 y hasta el recuento de 1,000,000. ¡Esto bloqueará tu navegador por bastante tiempo! Sin mencionar la cantidad de datos volando sobre el cable ... – matb33
@ matb33, ¿hay una mejor solución para el problema de descarga? –