Meteor Yayınını Anlamak / Abone Olmak


84

Bir listesini gösteren basit bir uygulama kurulumum var Projects. autopublishPaketi, müşteriye her şeyi göndermemek için kaldırdım .

 <template name="projectsIndex">    
   {{#each projects}}      
     {{name}}
   {{/each}}
 </template>

Açıldığında autopublish, bu tüm projeleri görüntüler:

if Meteor.isClient
  Template.projectsIndex.projects = Projects.find()

Kaldırıldığında, ek olarak yapmam gerekiyor:

 if Meteor.isServer
   Meteor.publish "projects", ->
     Projects.find()
 if Meteor.isClient
   Meteor.subscribe "projects"
   Template.projectsIndex.projects = Projects.find()

Öyleyse, istemci tarafı find()yönteminin yalnızca sunucu tarafından yayınlanan kayıtları aradığını söylemek doğru mu? Beni heyecanlandırıyor çünkü sadece bir find()kez aramam gerektiğini hissettim .

Yanıtlar:


286

Koleksiyonlar, yayınlar ve abonelikler, bazen kafa karıştırıcı terminoloji ile güçlendirilen sık sık kafa karışıklığını önlemek için dokümantasyonun daha ayrıntılı olarak tartışabileceği karmaşık bir Meteor alanıdır .

İşte en Sacha Greif (co-yazar DiscoverMeteor ) bir slayt yayınlar ve abonelikler açıklayan:

abonelikler

Neden find()birden fazla aramanız gerektiğini tam olarak anlamak için koleksiyonların, yayınların ve aboneliklerin Meteor'da nasıl çalıştığını anlamanız gerekir:

  1. MongoDB'de koleksiyonları tanımlarsınız. Henüz Meteor dahil değil. Bu koleksiyonlara veri tabanı kayıtları (ayrıca Mongo hem "dokümanları" olarak adlandırılan ve meteor , fakat bir "belgesi" bir veri tabanı kaydının daha genel, mesela, bir güncelleme özellikleri veya bir sorgu seçici belgelerdir çok - JavaScript içeren nesneler field: valueçifti).

  2. Sonra tanımlamak koleksiyonları Meteor sunucuda ile

    MyCollection = new Mongo.Collection('collection-name-in-mongo')
    

    Bu koleksiyonlar , MongoDB koleksiyonlarındaki tüm verileri içerir ve MyCollection.find({...})bunlar üzerinde çalıştırabilirsiniz , bu da bir imleç (bir dizi kayıt, aralarında yineleme ve geri döndürme yöntemleriyle) döndürür.

  3. Bu imleç (çoğu zaman ) bir dizi kaydı ( "kayıt kümesi" olarak adlandırılır) yayınlamak (göndermek) için kullanılır. . İsteğe bağlı olarak bu kayıtlardan yalnızca bazı alanları yayınlayabilirsiniz . Müşterilerin abone olduğu kayıt kümeleridir ( koleksiyonlar değil ) . Yayınlama, yeni bir müşteri her abone olduğunda çağrılan ve hangi kayıtların geri döndürüleceğini yönetmek için parametreler alabilen (örneğin, yalnızca o kullanıcının belgelerini döndürmek için bir kullanıcı kimliği) bir yayınlama işlevi tarafından yapılır .

  4. İstemcide , sunucudaki kayıtların bir kısmını kısmen yansıtan Minimongo koleksiyonlarınız vardır . "Kısmen", çünkü yalnızca bazı alanları ve "bazı kayıtları" içerebilirler çünkü genellikle istemciye yalnızca ihtiyaç duyduğu kayıtları, sayfa yüklemesini hızlandırmak için göndermek istersiniz ve yalnızca ihtiyaç duyduğu ve izinleri vardır Giriş.

    Minimongo, temelde, tamamen JavaScript'te Mongo'nun bellek içi, kalıcı olmayan bir uygulamasıdır. Bu istemcinin birlikte çalıştığı veritabanının yalnızca alt kümesini depolayan yerel bir önbellek görevi görür. İstemci (bul) üzerindeki sorgular, sunucuyla konuşmadan doğrudan bu önbellekten sunulur.

    Bu Minimongo koleksiyonları başlangıçta boştur. Tarafından doldurulur

    Meteor.subscribe('record-set-name')
    

    aramalar. Abone olunacak parametrenin bir koleksiyon adı olmadığını unutmayın; sunucunun aramada kullandığı kayıt kümesinin adıdır publish. subscribe()Arama bir müşteri abone kayıt kümesi sunucu koleksiyonundan kayıtların bir alt kümesini (örn En son 100 blog kayıtları), bütün veya her kayıttaki alanların bir alt kümesini (örneğin sadece - titleve date). Minimongo, gelen kayıtları hangi koleksiyona yerleştireceğini nasıl biliyor? Koleksiyonun adı olacaktır collectionyayımlamak işleyici yıllarda kullanılan argüman added, changedve removedgeri aramaları veya bu (çoğu zaman durum budur) eksikse, o sunucu üzerindeki MongoDB koleksiyonunun adı olacaktır.

Kayıtları değiştirme

Meteor'un işleri çok kolaylaştırdığı yer burasıdır: İstemcideki Minimongo koleksiyonundaki bir kaydı (belgeyi) değiştirdiğinizde, Meteor ona bağlı olan tüm şablonları anında güncelleyecek ve ayrıca değişiklikleri sunucuya geri gönderecek, bu da sırayla değişiklikleri MongoDB'de saklayacak ve bu belgeyi içeren bir kayıt setine abone olan uygun istemcilere gönderecektir. Buna gecikme telafisi denir ve Meteor'un yedi temel ilkesinden biridir .

Birden çok abonelik

Farklı kayıtları çeken bir grup aboneliğiniz olabilir, ancak bunların tümü _id,. Bu açık bir şekilde açıklanmıyor, ancak Meteor belgelerinde ima ediliyor:

Bir kayıt setine abone olduğunuzda, sunucuya istemciye kayıt göndermesini söyler. İstemci, bu kayıtları yerel Minimongo koleksiyonlarında, collectionyayın işleyicisinde kullanılan argümanla aynı adla saklar added,changed ve removedgeri aramalar. Siz istemcide Mongo.Collection eşleşen koleksiyon adıyla bildirene kadar Meteor gelen öznitelikleri sıraya koyacaktır.

Ne izah değil siz böyle olur yok açıkça kullanmak added, changedve removedçoğu zaman hangi - ya hiç işleyicileri yayımlamak. Bu en yaygın durumda, koleksiyon argümanı (şaşırtıcı olmayan bir şekilde) 1. adımda sunucuda beyan ettiğiniz MongoDB koleksiyonunun adından alınmıştır. Ancak bunun anlamı, farklı adlara sahip farklı yayınlara ve aboneliklere sahip olabileceğiniz ve tüm kayıtlar, istemcide aynı koleksiyonda yer alır. Meteor , en üst düzey alanlar düzeyine kadar , belgeler arasında, aboneliklerin üst üste gelebilmesi için belirli bir birleştirme gerçekleştirmeye özen gösterir - farklı üst düzey alanları müşteriye yan yana ve istemciye gönderen işlevler yayınlayın. koleksiyon olacakiki alan kümesinin birliği .

Örnek: istemcide aynı koleksiyonu dolduran birden çok abonelik

Farklı şeyler yapsa da hem sunucuda hem de istemcide aynı şekilde ilan ettiğiniz bir BlogPosts koleksiyonunuz var:

BlogPosts = new Mongo.Collection('posts');

İstemcide, BlogPostskayıtları şuradan alabilir:

  1. en son 10 blog gönderisine abonelik

    // server
    Meteor.publish('posts-recent', function publishFunction() {
      return BlogPosts.find({}, {sort: {date: -1}, limit: 10});
    }
    // client
    Meteor.subscribe('posts-recent');
    
  2. mevcut kullanıcının gönderilerine abonelik

    // 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. en popüler gönderilere abonelik

  4. vb.

Tüm bu belgeler , sunucudaki koleksiyon postsaracılığıyla MongoDB'deki koleksiyondan gelir ve istemcide koleksiyonda BlogPostsson BlogPostsbulur.

Artık neden find()birden fazla aramanız gerektiğini anlayabiliriz - ikinci kez müşteride olmak, çünkü tüm aboneliklerden belgeler aynı koleksiyonda yer alacak ve yalnızca ilgilendiğiniz kişileri getirmeniz gerekecek. Örneğin, istemcideki en son gönderileri almak için sunucudan gelen sorguyu yansıtmanız yeterlidir:

var recentPosts = BlogPosts.find({}, {sort: {date: -1}, limit: 10});

Bu, müşterinin şimdiye kadar aldığı tüm belgelere / kayıtlara, hem en çok okunan gönderilere hem de kullanıcının gönderilerine bir imleç döndürecektir. ( teşekkürler Geoffrey ).


10
Bu harika. BlogPosts.find({})Her iki yayına da abone olduktan sonra müşteri üzerinde yaparsanız ne olacağı belki de bahsetmeye değerdir - yani, müşteride bulunan tüm belgelerin / kayıtların, hem en çok okunan gönderiler hem de kullanıcının gönderileri için bir imleç döndürür. SO ile ilgili soru soranın bununla kafasının karıştığı başka sorular da gördüm.
Geoffrey Booth

3
Bu harika. Teşekkürler. Ek olarak, Meteor.users () koleksiyonu, istemci tarafında otomatik olarak yayınlandığı için biraz kafa karıştırıcı oluyor. Kullanıcılar () koleksiyonunu belirtmek için yukarıdaki yanıta biraz eklenebilir mi?
Jimmy MG Lim

3
Başlangıçta sorulandan çok daha fazlası olsa bile @DVG'nin bu harika yazıyı kabul edilen cevap olarak işaretlemesi gerektiğini düşünüyorum. Teşekkürler Dan.
fizyocoder

1
Teşekkürler @DanDascalescu, Benim için çok açıklığa kavuşan harika bir açıklama, açıklamanızı okuduktan sonra "koleksiyonlar" ile ilgili meteor belgelerini takip ederken BlogPostsbir koleksiyon olmadığını düşündüğüm tek şey, "ekle", "güncelleme" gibi yöntemlere sahip döndürülen nesne "..etc, ve gerçek koleksiyon hem postsistemcide hem de sunucudadır.
UXE

4
Sadece abone olduğunuz kayıt kümesini aramak mümkün mü? Olduğu gibi, Minimongo db'yi yerel olarak sorgulamak yerine javascript'imdeki kayıt setini doğrudan almak mümkün mü?
Jimmy Knoot

27

Evet, istemci tarafı find () yalnızca Minimongo'daki istemcide bulunan belgeleri döndürür. Gönderen docs :

İstemcide bir Minimongo örneği oluşturulur. Minimongo, esasen, tamamen JavaScript'te Mongo'nun bellek içi, kalıcı olmayan bir uygulamasıdır. Bu istemcinin birlikte çalıştığı veritabanının yalnızca alt kümesini depolayan yerel bir önbellek görevi görür. İstemcideki (bul) sorgular, sunucuyla konuşmadan doğrudan bu önbellekten sunulur.

Dediğiniz gibi, publish () müşterinin hangi belgelere sahip olacağını belirtir.


1

Buradaki temel pratik kural şudur publishve subscribeddeğişken isimleri istemci ve sunucu tarafında aynı olmalıdır.

Mongo DB ve istemci tarafındaki koleksiyon adları aynı olmalıdır.

Adlandırılmış koleksiyonum için yayınla ve abone olduğumu varsayalım o employeeszaman kod şöyle görünür


sunucu tarafı

Burada varanahtar kelimenin kullanımı isteğe bağlıdır (koleksiyonu bu dosyaya yerel yapmak için bu anahtar kelimeyi kullanın).

CollectionNameOnServerSide = new Mongo.Collection('employees');   

Meteor.publish('employeesPubSub', function() { 
    return CollectionNameOnServerSide.find({});     
});

istemci tarafı .js dosyası

CollectionNameOnClientSide = new Mongo.Collection('employees');
var employeesData = Meteor.subscribe('employeesPubSub');

Template.templateName.helpers({
  'subcribedDataNotAvailable' : function(){
        return !employeesData.ready();
    },
   'employeeNumbers' : () =>{
       CollectionNameOnClientSide.find({'empId':1});
  }
});

istemci tarafı .html dosyası

Burada, subcribedDataNotAvailableverilerin istemci tarafında hazır olup olmadığını bilmek için yardımcı yöntemi kullanabiliriz , veri hazırsa, employeeNumbersyardımcı yöntemi kullanarak çalışan numaralarını yazdırabiliriz .

<TEMPLATE name="templateName">
{{#if subcribedDataNotAvailable}}
   <h1> data loading ... </h1>
 {{else}}
  {{#each employeeNumbers }}
     {{this}}
  {{/each}}
 {{/if}}
<TEMPLATE>

0
// on the server
Meteor.publish('posts', function() {

    return Posts.find();

});

// on the client
Meteor.subscribe('posts');
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.