Meteor 게시 / 구독 이해


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

컬렉션, 간행물 및 구독은 Meteor의 까다로운 영역으로, 문서에서 더 자세히 논의 할 수있어 잦은 혼동 을 피할 수 있습니다. 종종 혼동 되는 용어로 인해 증폭됩니다 .

다음은 Sacha Greif ( DiscoverMeteor의 공동 저자 )가 발행물과 구독을 하나의 슬라이드로 설명합니다.

구독

find()두 번 이상 호출해야하는 이유를 올바르게 이해하려면 Meteor에서 컬렉션, 출판 및 구독이 작동하는 방식을 이해해야합니다.

  1. MongoDB에서 컬렉션을 정의합니다. 아직 Meteor가 관련되지 않았습니다. 이 컬렉션은 포함 된 데이터베이스 레코드가 (또한 몽고 모두에 의해 "문서"라는 및 유성 하지만, "문서는"데이터베이스 레코드보다 더 일반적이며, 예를 들어, 업데이트 사양 또는 쿼리 선택이 문서입니다 - 자바 스크립트가 포함 된 객체 field: value쌍).

  2. 그런 다음 Meteor 서버에서 다음을 사용하여 컬렉션 을 정의 합니다 .

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

    이러한 컬렉션에는 MongoDB 컬렉션의 모든 데이터가 포함되어 있으며 MyCollection.find({...})이를 실행 하면 커서 가 반환됩니다 (레코드 집합,이를 반복하고 반환하는 메서드 포함).

  3. 이 커서는 (대부분의 경우) 레코드 집합 ( "레코드 집합" 이라고 함) 을 게시 (전송)하는 데 사용됩니다 . 선택적 으로 해당 레코드의 일부 필드 만 게시 할 수 있습니다 . 이 기록 세트 (입니다 하지 클라이언트가 있다고 컬렉션) 가입 에. 게시는 새 클라이언트가 구독 할 때마다 호출되고 반환 할 레코드를 관리하기위한 매개 변수를 사용할 수 있는 게시 함수에 의해 수행됩니다 (예 : 해당 사용자의 문서 만 반환하는 사용자 ID).

  4. 클라이언트에서 , 당신은 Minimongo의 컬렉션을 부분적으로 반영 일부 서버에서 기록을. "부분적으로"당신이 일반적으로 페이지로드 속도를 높이기 위해,가 필요한 레코드 만 클라이언트에 보낼 및 만이 필요하기 때문에 그들이 "기록의 일부를"일부 필드 포함하고 수 있기 때문에 에 권한이 접속하다.

    Minimongo는 본질적으로 순수 JavaScript에서 Mongo의 비 영구적 인 메모리 내 구현입니다. 이 클라이언트가 작업하는 데이터베이스의 하위 집합 만 저장하는 로컬 캐시 역할을합니다. 클라이언트 (find)에 대한 쿼리는 서버와 통신하지 않고이 캐시에서 직접 제공됩니다.

    이러한 Minimongo 컬렉션은 처음에는 비어 있습니다. 그들은

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

    전화. 구독 할 매개 변수 는 컬렉션 이름이 아닙니다. 서버가 호출에 사용한 레코드 세트 의 이름입니다 publish. 이 subscribe()호출은 클라이언트를 레코드 세트 (예 : 가장 최근의 블로그 게시물 100 개)에있는 레코드의 하위 집합으로, 각 레코드의 필드 전체 또는 하위 집합 (예 : titledate)에 구독합니다 . Minimongo는 들어오는 레코드를 어떤 컬렉션에 저장할지 어떻게 알 수 있습니까? 컬렉션의 이름은 collection게시 처리기의 added, changedremoved콜백에 사용되는 인수가 되거나 누락 된 경우 (대부분의 경우) 서버에있는 MongoDB 컬렉션의 이름이됩니다.

레코드 수정

이것이 Meteor가 매우 편리하게 만드는 곳입니다. 클라이언트의 Minimongo 컬렉션에서 레코드 (문서)를 수정할 때 Meteor는 이에 의존하는 모든 템플릿을 즉시 업데이트하고 변경 사항을 서버로 다시 보냅니다. MongoDB에 변경 사항을 저장하고 해당 문서를 포함한 레코드 세트를 구독 한 적절한 클라이언트로 전송합니다. 이를 지연 보상 이라고 하며 Meteor7 가지 핵심 원칙 중 하나입니다 .

여러 구독

다른 레코드를 가져 오는 여러 구독을 가질 수 있지만 _id. 이것은 명확하게 설명되지 않지만 Meteor 문서에 암시되어 있습니다.

레코드 세트를 구독하면 서버에 레코드를 클라이언트로 보내도록 지시합니다. 와 동일한 이름을 가진 클라이언트를 저장 지역 Minimongo 컬렉션에서이 기록 collection에 사용되는 인수는 핸들러의 게시 added, changedremoved콜백. Meteor는 클라이언트에서 일치하는 컬렉션 이름으로 Mongo.Collection을 선언 할 때까지 들어오는 속성을 큐에 넣습니다.

어떤 설명되지 것은 당신이 때 발생하는 것입니다 하지 않습니다 명시 적으로 사용 added, changed그리고 removed대부분의 시간이다 -, 또는 전혀 핸들러를 게시 할 수 있습니다. 이 가장 일반적인 경우 컬렉션 인수는 1 단계에서 서버에서 선언 한 MongoDB 컬렉션의 이름에서 가져옵니다. 레코드는 클라이언트의 동일한 컬렉션에 저장됩니다. 의 수준까지 최고 수준의 필드 에 문서를 나란히하고 클라이언트에서 클라이언트 작업 측에 다른 최상위 필드를 발송 기능을 게시 - 유성 구독이 겹칠 수 있도록 문서 사이에 일련의 조합을 수행 할을 담당 컬렉션은두 필드 집합의 합집합 .

예 : 클라이언트에서 동일한 컬렉션을 채우는 여러 구독

다른 작업을 수행하더라도 서버와 클라이언트 모두에서 동일한 방식으로 선언하는 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. 기타

이 모든 문서 는 서버 postsBlogPosts컬렉션을 통해 MongoDB 의 컬렉션에서 가져와 BlogPosts클라이언트 의 컬렉션으로 끝납니다 .

이제 find()두 번 이상 호출해야하는 이유를 이해할 수 있습니다 . 두 번째는 모든 구독의 문서가 동일한 컬렉션에 있고 관심있는 문서 만 가져와야하기 때문입니다. 예를 들어 클라이언트에서 가장 최근 게시물을 가져 오려면 서버에서 쿼리를 미러링하면됩니다.

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

이렇게하면 클라이언트가 지금까지받은 모든 문서 / 레코드, 상위 게시물과 사용자 게시물 모두에 커서가 반환됩니다. ( Geoffrey에게 감사드립니다 ).


10
이것은 훌륭합니다. 언급 할 가치가있는 것은 BlogPosts.find({})두 발행물을 모두 구독 한 후 클라이언트에서 수행하는 경우 발생하는 일입니다. 즉, 현재 클라이언트에있는 모든 문서 / 레코드, 상위 게시물 및 사용자 게시물의 커서를 반환합니다. 질문자가 이것으로 혼란스러워하는 다른 질문을 보았습니다.
Geoffrey Booth

3
이것은 훌륭합니다. 감사. 또한 Meteor.users () 컬렉션은 클라이언트 측에 자동 게시되기 때문에 약간 혼란스러워집니다. users () 컬렉션을 설명하기 위해 위의 답변에 약간을 추가 할 수 있습니까?
Jimmy MG Lim

3
원래 요청한 것보다 훨씬 더 많더라도 @DVG는이 ​​훌륭한 글을 받아 들여진 답변으로 표시해야한다고 생각합니다. 고마워 댄.
physiocoder 2014

1
감사합니다 @DanDascalescu, 나를 위해 많은 것을 정리 한 훌륭한 설명, 설명을 읽은 후 "컬렉션"에 대한 유성 문서를 따를 때 컬렉션 BlogPosts이 아니라고 생각하는 유일한 것은 "삽입", "업데이트"와 같은 메서드가있는 반환 된 객체 "..etc, 실제 컬렉션은 posts클라이언트와 서버에도 있습니다.
UXE 2014 년

4
구독 한 레코드 세트 만 호출 할 수 있습니까? 에서와 같이 Minimongo db를 로컬로 쿼리하는 대신 내 자바 스크립트에서 레코드 세트를 직접 가져올 수 있습니까?
Jimmy Knoot 2014 년

27

예, 클라이언트 측 find ()는 Minimongo의 클라이언트에있는 문서 만 반환합니다. 에서 문서 :

클라이언트에서 Minimongo 인스턴스가 생성됩니다. Minimongo는 본질적으로 순수 JavaScript에서 Mongo의 비 영구적 인 메모리 내 구현입니다. 이 클라이언트가 작업하는 데이터베이스의 하위 집합 만 저장하는 로컬 캐시 역할을합니다. 클라이언트 (find)에 대한 쿼리는 서버와 통신하지 않고이 캐시에서 직접 제공됩니다.

당신이 말했듯이, publish ()는 클라이언트가 가질 문서를 ​​지정합니다.


1

기본 엄지 손가락의 규칙은 여기 publishsubscribed변수 이름은 클라이언트와 서버 측에서 동일해야합니다.

Mongo DB와 클라이언트 측의 컬렉션 이름은 동일해야합니다.

내 컬렉션에 대해 게시 및 구독을 사용하고 있다고 가정하면 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>

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

    return Posts.find();

});

// on the client
Meteor.subscribe('posts');
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.