MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Entendendo a publicação/assinatura do Meteor


Coleções, publicações e assinaturas são uma área complicada do Meteor, que a documentação poderia discutir com mais detalhes, para evitar confusões frequentes, que às vezes são amplificadas pela terminologia confusa.

Aqui está Sacha Greif (coautor de DiscoverMeteor) explicando publicações e assinaturas em um slide:



Para entender corretamente por que você precisa chamar find() mais de uma vez, você precisa entender como as coleções, publicações e assinaturas funcionam no Meteor:

  1. Você define coleções no MongoDB. Nenhum Meteor envolvido ainda. Essas coleções contêm registros de banco de dados (também chamado de "documentos" por Mongo e Meteor, mas um "documento" é mais geral do que um registro de banco de dados; por exemplo, uma especificação de atualização ou um seletor de consulta também são documentos - objetos JavaScript contendo field:value pares).

  2. Então você define as coleções no servidor Meteor com
    MyCollection = new Mongo.Collection('collection-name-in-mongo')
    

    Essas coleções contêm todos os dados das coleções do MongoDB e você pode executar MyCollection.find({...}) neles, que retornará um cursor (um conjunto de registros, com métodos para iterar por eles e retorná-los).

  3. Este cursor é (na maioria das vezes) usado para publicar (enviar) um conjunto de registros (chamado de "conjunto de registros" ). Opcionalmente, você pode publicar apenas algumas campos desses registros. São conjuntos de registros (não coleções) que os clientes assinam para. A publicação é feita por uma função de publicação, que é chamada toda vez que um novo cliente se inscreve e que pode receber parâmetros para gerenciar quais registros retornar (por exemplo, um ID de usuário, para retornar apenas os documentos desse usuário).

  4. No cliente , você tem coleções do Minimongo que parcialmente espelhar algum dos registros do servidor. "Parcialmente" porque podem conter apenas alguns dos campos, e "alguns dos registros" porque normalmente você quer enviar ao cliente apenas os registros que ele precisa, para acelerar o carregamento da página, e apenas aqueles que ele precisa e tem permissão para acessar.

    O Minimongo é essencialmente uma implementação na memória e não persistente do Mongo em JavaScript puro. Ele serve como um cache local que armazena apenas o subconjunto do banco de dados com o qual esse cliente está trabalhando. As consultas no cliente (localizar) são atendidas diretamente desse cache, sem falar com o servidor.

    Essas coleções do Minimongo estão inicialmente vazias. Eles são preenchidos por
    Meteor.subscribe('record-set-name')
    

    chamadas. Observe que o parâmetro para assinar não é um nome de coleção; é o nome de um conjunto de registros que o servidor usou na publicação ligar. O subscrever() call inscreve o cliente em um conjunto de registros - um subconjunto de registros da coleção do servidor (por exemplo, 100 postagens de blog mais recentes), com todos ou um subconjunto dos campos em cada registro (por exemplo, apenas title e data ). Como o Minimongo sabe em qual coleção colocar os registros recebidos? O nome da coleção será a coleção argumento usado no manipulador de publicação adicionado , alterado , e removido callbacks, ou se estiverem faltando (o que é o caso na maioria das vezes), será o nome da coleção do MongoDB no servidor.

Modificando registros


É aqui que o Meteor torna as coisas muito convenientes:quando você modifica um registro (documento) na coleção Minimongo no cliente, o Meteor atualizará instantaneamente todos os modelos que dependem dele e também enviará as alterações de volta ao servidor, que por sua vez armazenará as alterações no MongoDB e as enviará aos clientes apropriados que se inscreveram em um conjunto de registros incluindo esse documento. Isso é chamado de compensação de latência e é um dos sete princípios fundamentais do Meteor.

Várias assinaturas


Você pode ter várias assinaturas que extraem registros diferentes, mas todas elas acabarão na mesma coleção no cliente se vierem da mesma coleção no servidor, com base em seu _id . Isso não é explicado claramente, mas está implícito nos documentos do Meteor:

Quando você assina um conjunto de registros, ele informa ao servidor para enviar registros ao cliente. O cliente armazena esses registros em coleções locais do Minimongo, com o mesmo nome da coleção argumento usado no manipulador de publicação adicionado , alterado , e removido retornos de chamada. O Meteor irá enfileirar os atributos de entrada até que você declare o Mongo.Collection no cliente com o nome da coleção correspondente.

O que não é explicado é o que acontece quando você não use explicitamente adicionado , alterado e removido , ou publique manipuladores - o que é na maioria das vezes. Nesse caso mais comum, o argumento de coleção é (sem surpresa) retirado do nome da coleção do MongoDB que você declarou no servidor na etapa 1. Mas o que isso significa é que você pode ter publicações e assinaturas diferentes com nomes diferentes, e todos os registros terminarão na mesma coleção no cliente. Até o nível dos campos de nível superior , o Meteor cuida de realizar uma união definida entre os documentos, de forma que as assinaturas possam se sobrepor - publicar funções que enviam diferentes campos de nível superior para o cliente trabalham lado a lado e no cliente, o documento na coleção será a união dos dois conjuntos de campos.

Exemplo:várias assinaturas preenchendo a mesma coleção no cliente


Você tem uma coleção BlogPosts, que você declara da mesma maneira no servidor e no cliente, embora faça coisas diferentes:
BlogPosts = new Mongo.Collection('posts');

No cliente, BlogPosts pode obter registros de:

  1. uma assinatura das 10 postagens mais recentes do blog
    // server
    Meteor.publish('posts-recent', function publishFunction() {
      return BlogPosts.find({}, {sort: {date: -1}, limit: 10});
    }
    // client
    Meteor.subscribe('posts-recent');
    

  2. uma assinatura das postagens do usuário atual
    // server
    Meteor.publish('posts-current-user', function publishFunction() {
      return BlogPosts.find({author: this.userId}, {sort: {date: -1}, limit: 10});
      // this.userId is provided by Meteor - http://docs.meteor.com/#publish_userId
    }
    Meteor.publish('posts-by-user', function publishFunction(who) {
      return BlogPosts.find({authorId: who._id}, {sort: {date: -1}, limit: 10});
    }
    
    // client
    Meteor.subscribe('posts-current-user');
    Meteor.subscribe('posts-by-user', someUser);
    

  3. uma assinatura das postagens mais populares
  4. etc.

Todos esses documentos vêm dos posts coleção no MongoDB, através do BlogPosts coleção no servidor e acabam no BlogPosts cobrança no cliente.

Agora podemos entender por que você precisa chamar find() mais de uma vez - a segunda vez no cliente, porque os documentos de todas as assinaturas acabarão na mesma coleção e você precisa buscar apenas aqueles que lhe interessam. Por exemplo, para obter as postagens mais recentes no cliente, basta espelhar a consulta do servidor:
var recentPosts = BlogPosts.find({}, {sort: {date: -1}, limit: 10});

Isso retornará um cursor para todos os documentos/registros que o cliente recebeu até agora, tanto as postagens principais quanto as postagens do usuário. (obrigado Godofredo).