उल्का प्रकाशन / सदस्यता को समझना


84

मुझे एक सरल ऐप मिला है, जिसकी एक सूची दिखाता है Projects। मैंने autopublishपैकेज निकाल दिया है ताकि मैं क्लाइंट को सब कुछ न भेजूं।

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

जब autopublishचालू किया गया था, तो यह सभी परियोजनाओं को प्रदर्शित करेगा:

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

इसके हटाए जाने के साथ, मुझे इसके अतिरिक्त करना होगा:

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

तो, क्या यह कहना सही है कि क्लाइंट-साइड find()विधि केवल उन रिकॉर्ड्स को खोजती है जो सर्वर-साइड से प्रकाशित किए गए हैं? यह मुझे ऊपर ले जा रहा है क्योंकि मुझे लगा कि मुझे केवल find()एक बार फोन करना चाहिए ।

जवाबों:


286

संग्रह, प्रकाशन और सदस्यताएँ उल्का का एक मुश्किल क्षेत्र है, कि प्रलेखन अधिक विस्तार से चर्चा कर सकता है, ताकि बार-बार भ्रम से बचा जा सके , जो कभी-कभी भ्रमित शब्दावली से बढ़ जाता है

यहाँ के साचा दु: ख (के सह लेखक DiscoverMeteor ) एक स्लाइड में प्रकाशन और सदस्यता समझा:

सदस्यता

यह समझने के लिए कि आपको find()एक से अधिक बार कॉल करने की आवश्यकता क्यों है , आपको यह समझने की आवश्यकता है कि उल्का में संग्रह, प्रकाशन और सदस्यता कैसे काम करते हैं:

  1. आप MongoDB में संग्रह परिभाषित करते हैं। कोई उल्का अभी तक शामिल नहीं है। इन संग्रहों में मैंगो और उल्का दोनों द्वारा डेटाबेस रिकॉर्ड ("दस्तावेज" भी कहा जाता है , लेकिन डेटाबेस रिकॉर्ड में "दस्तावेज़" अधिक सामान्य है, उदाहरण के लिए, एक अद्यतन विनिर्देश या एक क्वेरी चयनकर्ता भी दस्तावेज़ हैं - जावास्क्रिप्ट ऑब्जेक्ट्स जोड़े वाले)।field: value

  2. फिर आप उल्का सर्वर पर संग्रह को परिभाषित करते हैं

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

    इन संग्रहों में MongoDB संग्रह के सभी डेटा शामिल हैं , और आप उन MyCollection.find({...})पर चला सकते हैं, जो एक कर्सर (रिकॉर्ड का एक सेट, उनके माध्यम से पुनरावृति करने के तरीकों के साथ और उन्हें वापस लौटाएगा)।

  3. यह कर्सर (अधिकांश समय) रिकॉर्ड का एक सेट ( "रिकॉर्ड सेट" कहा जाता है) प्रकाशित करने के लिए उपयोग किया जाता है । आप वैकल्पिक रूप से उन अभिलेखों से केवल कुछ फ़ील्ड प्रकाशित कर सकते हैं । यह रिकॉर्ड सेट ( संग्रह नहीं ) है जो ग्राहक सदस्यता लेते हैं। प्रकाशन एक प्रकाशन फ़ंक्शन द्वारा किया जाता है , जिसे हर बार एक नए ग्राहक की सदस्यता मिलती है, और जो कि प्रबंधन करने के लिए पैरामीटर ले सकता है (उदाहरण के लिए उपयोगकर्ता आईडी, केवल उस उपयोगकर्ता के दस्तावेज़ वापस करने के लिए)।

  4. क्लाइंट पर , आपके पास मिनिमॉन्गो संग्रह हैं जो आंशिक रूप से सर्वर से रिकॉर्ड के कुछ दर्पण हैं । "आंशिक रूप से" क्योंकि उनमें केवल कुछ फ़ील्ड हो सकते हैं, और "कुछ रिकॉर्ड्स" क्योंकि आप आमतौर पर क्लाइंट को केवल उन रिकॉर्ड्स को भेजना चाहते हैं, जो पेज लोड करने की गति बढ़ाते हैं, और केवल उन्हीं की आवश्यकता होती है और जिनके पास अनुमति है पहुंच।

    मिनिमॉन्गो मूल रूप से एक शुद्ध-स्मृति है, शुद्ध जावास्क्रिप्ट में मोंगो का निरंतर-कार्यान्वयन। यह एक स्थानीय कैश के रूप में कार्य करता है जो उस डेटाबेस के सबसेट को स्टोर करता है जिसके साथ यह क्लाइंट काम कर रहा है। सर्वर से बात किए बिना, क्लाइंट (खोज) पर क्वेरीज़ सीधे इस कैश से दी जाती हैं।

    ये मिनीमोंगो संग्रह शुरू में खाली हैं। वे भर रहे हैं

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

    कहता है। ध्यान दें कि सदस्यता के लिए पैरामीटर एक संग्रह नाम नहीं है; यह एक रिकॉर्ड सेट का नाम है जिसे सर्वर publishकॉल में उपयोग करता है । subscribe()कॉल एक करने के लिए ग्राहक सब्सक्राइब रिकॉर्ड सेट सब के साथ (जैसे हाल ही में 100 ब्लॉग पोस्ट) सर्वर संग्रह से रिकॉर्ड के सबसेट, या एक (केवल उदाहरण के लिए प्रत्येक रिकॉर्ड में फ़ील्ड के सबसेट - titleऔर date)। मिनिमॉन्गो को आने वाले रिकॉर्ड्स को रखने के लिए किस संग्रह में पता है? संग्रह का नाम होगा collectionप्रकाशित हैंडलर दशक में उपयोग किया तर्क added, changedऔर removedकॉलबैक, या अगर उन (इस स्थिति समय के सबसे अधिक है) याद कर रहे हैं, यह सर्वर पर MongoDB संग्रह का नाम हो जाएगा।

रिकॉर्ड को संशोधित करना

यह वह जगह है जहां उल्का चीजों को बहुत सुविधाजनक बनाती है: जब आप ग्राहक पर मिनिमोंगो संग्रह में एक रिकॉर्ड (दस्तावेज़) को संशोधित करते हैं, तो उल्का तुरंत उस पर निर्भर सभी टेम्प्लेट को अपडेट कर देगा, और सर्वर में परिवर्तन भी वापस भेज देगा, जो बदले में MongoDB में परिवर्तनों को संग्रहीत करेगा और उन्हें उन उपयुक्त ग्राहकों को भेजेगा जिन्होंने उस दस्तावेज़ सहित रिकॉर्ड सेट की सदस्यता ली है। इसे विलंबता क्षतिपूर्ति कहा जाता है और यह उल्का के सात मूल सिद्धांतों में से एक है

एकाधिक सदस्यताएँ

आपके पास सदस्यता का एक गुच्छा हो सकता है जो अलग-अलग रिकॉर्ड में खींचते हैं, लेकिन वे सभी क्लाइंट पर एक ही संग्रह में समाप्त हो जाएंगे यदि सर्वर पर एक ही संग्रह से आया हो, उनके आधार पर _id। यह स्पष्ट रूप से नहीं बताया गया है, लेकिन उल्का डॉक्स द्वारा निहित है:

जब आप रिकॉर्ड सेट की सदस्यता लेते हैं, तो यह क्लाइंट को रिकॉर्ड भेजने के लिए सर्वर को बताता है। ग्राहक दुकानों स्थानीय Minimongo संग्रह में इन रिकॉर्ड, के रूप में एक ही नाम के साथ collectionमें इस्तेमाल तर्क हैंडलर के प्रकाशित added, changedऔर removedकॉलबैक। उल्का आने वाली विशेषताओं को कतारबद्ध करेगा जब तक कि आप ग्राहक पर Mongo.Collection को मिलान संग्रह नाम के साथ घोषित नहीं करते।

स्पष्ट नहीं है कि क्या होता है जब आप स्पष्ट रूप से उपयोग नहीं करते हैं added, changedऔर removedसभी पर हैंडलर प्रकाशित करते हैं - जो कि ज्यादातर समय होता है। इस सबसे सामान्य मामले में, संग्रह तर्क है (बिना सोचे समझे) उस नाम से लिया गया MongoDB संग्रह जिसे आपने चरण 1 पर सर्वर पर घोषित किया था। लेकिन इसका मतलब यह है कि आपके पास अलग-अलग नामों के साथ अलग-अलग प्रकाशन और सदस्यताएँ हो सकती हैं, और सभी रिकॉर्ड क्लाइंट पर एक ही संग्रह में समाप्त हो जाएंगे। शीर्ष स्तर के क्षेत्रों के स्तर के नीचे , उल्का दस्तावेजों के बीच एक सेट यूनियन का प्रदर्शन करने के लिए ध्यान रखता है, जैसे कि सदस्यताएं ओवरलैप कर सकती हैं - उन कार्यों को प्रकाशित करती हैं जो क्लाइंट के लिए अलग-अलग शीर्ष स्तर के फ़ील्ड को कंधे से कंधा मिलाकर और क्लाइंट पर दस्तावेज़ में भेजती हैं। संग्रह होगाखेतों के दो सेटों का मिलन

उदाहरण: ग्राहक पर एक ही संग्रह भरने वाली कई सदस्यताएँ

आपके पास एक BlogPosts संग्रह है, जिसे आप सर्वर और क्लाइंट दोनों पर समान तरीके से घोषित करते हैं, भले ही यह अलग-अलग चीजें करता हो:

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

क्लाइंट पर, BlogPostsसे रिकॉर्ड प्राप्त कर सकते हैं:

  1. सबसे हाल ही में 10 ब्लॉग पोस्ट की सदस्यता

    // server
    Meteor.publish('posts-recent', function publishFunction() {
      return BlogPosts.find({}, {sort: {date: -1}, limit: 10});
    }
    // client
    Meteor.subscribe('posts-recent');
    
  2. वर्तमान उपयोगकर्ता के पदों की सदस्यता

    // 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. सबसे लोकप्रिय पदों के लिए एक सदस्यता

  4. आदि।

ये सभी दस्तावेज postsMongoDB में BlogPostsसंग्रह से सर्वर पर संग्रह के माध्यम से आते हैं , और BlogPostsक्लाइंट पर संग्रह में समाप्त होते हैं ।

अब हम समझ सकते हैं कि आपको find()एक से अधिक बार कॉल करने की आवश्यकता क्यों है - दूसरी बार क्लाइंट पर होने के कारण, क्योंकि सभी सदस्यता के दस्तावेज़ एक ही संग्रह में समाप्त हो जाएंगे, और आपको केवल उन लोगों को लाने की ज़रूरत है जिनकी आप परवाह करते हैं। उदाहरण के लिए, क्लाइंट पर सबसे हालिया पोस्ट प्राप्त करने के लिए, आप सर्वर से क्वेरी को मिरर करते हैं:

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

यह सभी दस्तावेज़ों / रिकॉर्डों के लिए एक कर्सर लौटाएगा जो क्लाइंट को अब तक, शीर्ष पदों और उपयोगकर्ता के पदों दोनों से मिला है। ( धन्यवाद जेफ्री )।


10
यह भी खूब रही। शायद ध्यान देने योग्य बात यह है कि यदि आप BlogPosts.find({})दोनों प्रकाशनों की सदस्यता लेने के बाद ग्राहक पर करते हैं, तो यह होता है - अर्थात यह ग्राहक के सभी दस्तावेजों / अभिलेखों का एक कर्सर लौटाएगा, जो शीर्ष पदों और उपयोगकर्ता के पदों दोनों पर होगा। मैंने SO पर अन्य प्रश्न देखे हैं जहाँ प्रश्नकर्ता इससे भ्रमित था।
ज्योफ्री बूथ

3
यह भी खूब रही। धन्यवाद। इसके अलावा, Meteor.users () कलेक्शन में टैड कन्फ्यूजिंग हो जाता है क्योंकि यह क्लाइंट साइड पर ऑटो प्रकाशित होता है। उपयोगकर्ताओं () संग्रह को निर्दिष्ट करने के लिए उपरोक्त उत्तर में थोड़ा जोड़ा जा सकता है?
जिमी एमजी लिम

3
यहां तक ​​कि अगर मूल रूप से मेरे विचार से अधिक पूछा गया तो @DVG को इस शानदार राइटअप को स्वीकृत उत्तर के रूप में चिह्नित करना चाहिए। धन्यवाद डैन।
फिजियोकोडर

1
धन्यवाद @DanDascalescu, महान स्पष्टीकरण जिसने मेरे लिए बहुत कुछ साफ कर दिया, केवल एक चीज जो आपके विवरण को पढ़ने के बाद "संग्रह" के बारे में उल्का डॉक्स के बाद मुझे लगता BlogPostsहै कि एक संग्रह नहीं है, इसकी लौटी हुई वस्तु जिसमें "सम्मिलित", "अपडेट" जैसी विधियां हैं "..etc, और वास्तविक संग्रह postsक्लाइंट और सर्वर में भी है।
UXE

4
क्या केवल उसी रिकॉर्ड के लिए कॉल करना संभव है जिसे आपने सब्सक्राइब किया है? जैसा कि, स्थानीय स्तर पर मिनीमोंगो डीबी को क्वेरी करने के बजाय सीधे मेरी जावास्क्रिप्ट में रिकॉर्ड प्राप्त करना संभव है?
जिमी नॉट ने

27

हां, क्लाइंट-साइड मिल () केवल उन दस्तावेजों को लौटाता है जो मिनिमोंगो में क्लाइंट पर हैं। से डॉक्स :

क्लाइंट पर, मिनिमोंगो उदाहरण बनाया जाता है। मिनिमॉन्गो मूल रूप से एक शुद्ध-स्मृति है, शुद्ध जावास्क्रिप्ट में मोंगो का निरंतर-कार्यान्वयन। यह एक स्थानीय कैश के रूप में कार्य करता है जो उस डेटाबेस के सबसेट को स्टोर करता है जिसके साथ यह क्लाइंट काम कर रहा है। सर्वर से बात किए बिना, क्लाइंट (खोज) पर क्वेरीज़ सीधे इस कैश से दी जाती हैं।

जैसा कि आप कहते हैं, प्रकाशित () निर्दिष्ट करता है कि ग्राहक के पास कौन से दस्तावेज़ होंगे।


1

यहां मूल अंगूठे नियम है publishऔर subscribedचर नाम क्लाइंट और सर्वर साइड पर समान होना चाहिए।

मानगो डीबी और ग्राहक पक्ष पर संग्रह नाम समान होना चाहिए।

मान लें कि मैं अपने संग्रह के लिए प्रकाशित और सदस्यता का उपयोग कर रहा हूं, employeesतो कोड जैसा दिखेगा


सर्वर साइड

यहां varकीवर्ड का उपयोग वैकल्पिक है (इस फ़ाइल में संग्रह को स्थानीय बनाने के लिए इस कीवर्ड का उपयोग करें)।

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

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

ग्राहक पक्ष .js फ़ाइल

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

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

ग्राहक पक्ष। html फ़ाइल

यहां हम यह subcribedDataNotAvailableजानने के लिए सहायक विधि का उपयोग कर सकते हैं कि क्या क्लाइंट की तरफ से डेटा तैयार है, यदि डेटा तैयार है तो employeeNumbersहेल्पर विधि का उपयोग करके कर्मचारी संख्या को प्रिंट करें ।

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.