Las colecciones, publicaciones y suscripciones son un área complicada de Meteor, que la documentación podría discutir con más detalle, para evitar confusiones frecuentes , que a veces se amplifican con terminología confusa .
Aquí está Sacha Greif (coautor de DiscoverMeteor ) explicando las publicaciones y suscripciones en una diapositiva:
Para comprender correctamente por qué necesita llamar find()
más de una vez, debe comprender cómo funcionan las colecciones, publicaciones y suscripciones en Meteor:
Define colecciones en MongoDB. Ningún meteorito involucrado todavía. Estas colecciones contienen los registros de base de datos (también llamados "documentos" por tanto Mongo y Meteor , pero un "documento" es más general que un registro de base de datos; por ejemplo, una especificación de actualizaciones o un selector de consultas son documentos demasiado - JavaScript objetos que contienen field: value
pares).
Luego, define colecciones en el servidor Meteor con
MyCollection = new Mongo.Collection('collection-name-in-mongo')
Estas colecciones contienen todos los datos de las colecciones de MongoDB, y puede ejecutarlas MyCollection.find({...})
, lo que devolverá un cursor (un conjunto de registros, con métodos para recorrerlos en iteración y devolverlos).
Este cursor se utiliza (la mayoría de las veces) para publicar (enviar) un conjunto de registros (denominado "conjunto de registros" ). Opcionalmente, puede publicar solo algunos campos de esos registros. Son conjuntos de registros ( no colecciones) a los que se suscriben los clientes . La publicación se realiza mediante una función de publicación , que se llama cada vez que se suscribe un nuevo cliente, y que puede tomar parámetros para administrar qué registros devolver (por ejemplo, una identificación de usuario, para devolver solo los documentos de ese usuario).
En el cliente , tiene colecciones de Minimongo que reflejan parcialmente algunos de los registros del servidor. "Parcialmente" porque pueden contener solo algunos de los campos y "algunos de los registros" porque normalmente desea enviar al cliente solo los registros que necesita, para acelerar la carga de la página, y solo aquellos que necesita y tiene permiso para acceso.
Minimongo es esencialmente una implementación no persistente en memoria de Mongo en JavaScript puro. Sirve como caché local que almacena solo el subconjunto de la base de datos con la que está trabajando este cliente. Las consultas en el cliente (buscar) se sirven directamente desde esta caché, sin hablar con el servidor.
Estas colecciones de Minimongo están inicialmente vacías. Están llenos de
Meteor.subscribe('record-set-name')
llamadas. Tenga en cuenta que el parámetro para suscribirse no es un nombre de colección; es el nombre de un conjunto de registros que utilizó el servidor en la publish
llamada. La subscribe()
llamada suscribe al cliente a un conjunto de registros : un subconjunto de registros de la colección del servidor (por ejemplo, las 100 publicaciones de blog más recientes), con todos o un subconjunto de los campos en cada registro (por ejemplo, solo title
y date
). ¿Cómo sabe Minimongo en qué colección colocar los registros entrantes? El nombre de la colección será el collection
argumento que se utiliza en los manejadores de publicar added
, changed
y removed
devoluciones de llamada, o si los desaparecidos (que es el caso de la mayor parte del tiempo), que será el nombre de la colección MongoDB en el servidor.
Modificar registros
Aquí es donde Meteor hace las cosas muy convenientes: cuando modifica un registro (documento) en la colección de Minimongo en el cliente, Meteor actualizará instantáneamente todas las plantillas que dependen de él y también enviará los cambios al servidor, que a su vez almacenará los cambios en MongoDB y los enviará a los clientes correspondientes que se hayan suscrito a un conjunto de registros que incluya ese documento. Esto se llama compensación de latencia y es uno de los siete principios básicos de Meteor .
Varias suscripciones
Puede tener un montón de suscripciones que obtengan diferentes registros, pero todas terminarán en la misma colección en el cliente si provienen de la misma colección en el servidor, según su _id
. Esto no se explica claramente, pero está implícito en los documentos de Meteor:
Cuando se suscribe a un conjunto de registros, le dice al servidor que envíe registros al cliente. El cliente almacena estos registros en colecciones locales Minimongo, con el mismo nombre que el collection
argumento utilizado en el manejador de publicar added
, changed
y removed
devoluciones de llamada. Meteor pondrá en cola los atributos entrantes hasta que declare Mongo.Collection en el cliente con el nombre de la colección correspondiente.
Lo que no se explica es lo que pasa cuando no se utiliza de forma explícita added
, changed
y removed
, o publicar los manipuladores en absoluto - que es la mayor parte del tiempo. En este caso más común, el argumento de la colección se toma (como era de esperar) del nombre de la colección de MongoDB que declaró en el servidor en el paso 1. Pero lo que esto significa es que puede tener diferentes publicaciones y suscripciones con diferentes nombres, y todas las los registros terminarán en la misma colección del cliente. Hasta el nivel de los campos de nivel superior , Meteor se encarga de realizar una unión establecida entre documentos, de modo que las suscripciones puedan superponerse: funciones de publicación que envían diferentes campos de nivel superior al trabajo del cliente en paralelo y en el cliente, el documento en el la colección será launión de los dos conjuntos de campos .
Ejemplo: múltiples suscripciones llenando la misma colección en el cliente
Tienes una colección BlogPosts, que declaras de la misma manera tanto en el servidor como en el cliente, aunque hace cosas diferentes:
BlogPosts = new Mongo.Collection('posts');
En el cliente, BlogPosts
puede obtener registros de:
una suscripción a las 10 publicaciones de blog más recientes
Meteor.publish('posts-recent', function publishFunction() {
return BlogPosts.find({}, {sort: {date: -1}, limit: 10});
}
Meteor.subscribe('posts-recent');
una suscripción a las publicaciones del usuario actual
Meteor.publish('posts-current-user', function publishFunction() {
return BlogPosts.find({author: this.userId}, {sort: {date: -1}, limit: 10});
}
Meteor.publish('posts-by-user', function publishFunction(who) {
return BlogPosts.find({authorId: who._id}, {sort: {date: -1}, limit: 10});
}
Meteor.subscribe('posts-current-user');
Meteor.subscribe('posts-by-user', someUser);
una suscripción a las publicaciones más populares
- etc.
Todos estos documentos provienen de la posts
colección en MongoDB, a través de la BlogPosts
colección en el servidor, y terminan en la BlogPosts
colección en el cliente.
Ahora podemos entender por qué necesita llamar find()
más de una vez: la segunda vez está en el cliente, porque los documentos de todas las suscripciones terminarán en la misma colección y solo debe buscar aquellos que le interesan. Por ejemplo, para obtener las publicaciones más recientes en el cliente, simplemente refleje la consulta desde el servidor:
var recentPosts = BlogPosts.find({}, {sort: {date: -1}, limit: 10});
Esto devolverá un cursor a todos los documentos / registros que el cliente ha recibido hasta ahora, tanto las publicaciones principales como las publicaciones del usuario. ( gracias Geoffrey ).
BlogPosts.find({})
en el cliente después de suscribirse a ambas publicaciones, es decir, devolverá un cursor de todos los documentos / registros que se encuentran actualmente en el cliente, tanto las publicaciones principales como las publicaciones del usuario. He visto otras preguntas sobre SO en las que el interrogador estaba confundido por esto.