javascript - started - meteor methods({
¿Cómo funciona el ejemplo de conteo de mensajes en Meteor? (4)
Tengo problemas para entender completamente este ejemplo de los documentos ... Intenté ejecutarlo de varias maneras para poder observar cómo funciona, etc.
¿Cómo te suscribes a esto? ¿Podemos incluir el código del lado del cliente necesario para que esto funcione?
¿Hay una colección llamada messages-count
? ¿Es una Room
una colección de mensajes? ¿Podemos incluir las definiciones de colección en el ejemplo?
¡Cualquier consejo sobre esto sería genial!
NOTA : este es el código tal como apareció cuando esta pregunta se publicó inicialmente (mayo de 2012). Es más simple ahora.
// server: publish the current size of a collection
Meteor.publish("messages-count", function (roomId) {
var self = this;
var uuid = Meteor.uuid();
var count = 0;
handle = Room.find({room_id: roomId}).observe({
added: function (doc, idx) {
count++;
self.set("messages-count", uuid, "count", count);
self.flush();
},
removed: function (doc, idx) {
count--;
self.set("messages-count", uuid, "count", count);
self.flush();
}
// don''t care about moved or changed
});
// remove data and turn off observe when client unsubs
self.onStop(function () {
handle.stop();
self.unset("messages-count", uuid, "count");
self.flush();
});
});
¿Qué pasaría si handle.stop () fuera comentado? Ver este ejemplo, ¿no funciona? Necesito poner OnStop () dentro de esta función: checkSharedBy () ??
Acabo de encontrar una solución al problema donde self.flush () está enviando miles de actualizaciones al cliente; simplemente use _.debounce al contar:
count = 0
throttled_subscription = _.debounce =>
@set ''items-count'', uuid, count: count
@flush()
, 10
handle = Items.find(selector).observe
added: =>
count++
throttled_subscription()
removed: =>
count--
throttled_subscription()
Esto solo configurará el recuento y purgará la suscripción después de 10 ms sin cambios.
Gracias a @possibilities en #meteor por la pista.
Como dijo Leonhardt Wille, la desventaja de esta solución es que el meteorito descarga toda la colección de elementos del servidor de Mongo solo para contarlos. Su solución en gist.github.com/3925008 es mejor, pero el contador no se actualizará cuando se inserten nuevos elementos.
Aquí está mi solución reactiva
Colecciones:
Players = new Meteor.Collection("players");
PlayersCounts = new Meteor.Collection("players_counts")
Servidor:
Meteor.publish("players_counts", function(){
var uuid = Meteor.uuid()
var self = this;
var unthrottled_setCount = function(){
cnt = Players.find({}).count()
self.set("players_counts", uuid, {count: cnt})
self.flush()
}
var setCount = _.throttle(unthrottled_setCount, 50)
var handle = Meteor._InvalidationCrossbar.listen({collection: "players"}, function(notification, complete){
setCount();
complete();
})
setCount();
self.complete()
self.flush()
self.onStop(function(){
handle.stop();
self.unset("players_counts", uuid, ["count"]);
self.flush();
});
});
Cliente:
Meteor.subscribe("players_counts")
Template.leaderboard.total = function(){
var cnt = PlayersCounts.findOne({})
if(cnt) {
return cnt.count;
} else {
return null;
}
}
Gracias por incitarme a escribir 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 _id
único 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 solo documento en una colección llamada "counts"
. El documento tendrá dos campos: un ID de habitación con el ID de una habitación y el 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 de observar observeChanges
para 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 al 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 a los observeChanges
, se observeChanges
una cantidad de devoluciones de llamadas added
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 onStop
la suscripción (ya sea manualmente o al desconectarse). Este manejador elimina los atributos del cliente y elimina el funcionamiento de los 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 a Meteor. Primero, necesitamos una Mongo.Collection
que contendrá nuestro documento de recuentos calculado. 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");
Entonces 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: la ID de la habitación actual. Envolví esto dentro de Deps.autorun
para que cuando 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"));
});
Finalmente, tenemos el documento en Counts
y podemos usarlo como cualquier otra colección de 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.");