[cookbook] Meteor Collection's Cursors #2

Meteor Collection's Cursors #2 Introduction

저번시간에 collection에 대해서 알아보았습니다. find 까지 설명을 해드렸고, 나머지는 CRUD의 간단한 단계이기 때문에 설명을 더 하지는 않겠습니다.

이번시간에는 cursor에 대해서 알아봅니다. cursor를 생성하기 위해서는 find 명령을 사용합니다. cursor는 각종 함수와 data(document)로 이루어져 있으며, data에 접근하기 위해서는 forEach, map, fetch, count 명령을 사용합니다. 그럼 이 명령어에 대해서 알아보겠습니다.

database

Reactivity Concept

Meteor는 reactivity 컨셉을 가지고 있습니다. 이는 session, collection 과 밀접한 관계가 있습니다. 이것의 변화가 일어날 때, 그것을 감지할 수 있습니다. 이것에 대한 조건이 있는데, 아래와 같습니다.

위 3개의 API에 전달되는 function은 reactivity context 를 가지게 되며, 이 context 안에서만 변화값이 감지되어 표현될 수 있습니다.

아래 설명할 collection access operator 들이 모두 이와 관련이 있으니, 참고하세요.

cursor.count

cursor에 포함된 데이타의 갯수를 리턴합니다.

syntax

Number cursor.count()

client / server 구분없음.

example

var Users = new Meteor.Collection("users"); 

if (Meteor.is_client) {                     
  //
  // Meteor.ui.render 에 전달된 함수안에
  // count operator 사용합니다.
  // reactivity context 이기 때문에, 데이타의 변화는 바로 감지되어
  // 아래와 같이 document.body에 표현됩니다.
  //
  var frag = Meteor.ui.render(function () { 
    return "" + Users.find().count();       
  });                                       

  Meteor.startup(function() {               
    document.body.appendChild(frag);        
  });                                       
}                                           

client(firebug)에서 데이타를 입력해봅니다.

>>> Users.insert({num:1})
"99647fa3-1072-406b-80b6-9681d5c70890"

>>> Users.insert({num:1})   
"e9ccaab9-6854-4343-8a69-9d81b8989950"

화면에 바로 갱신되는 모습을 확인할 수 있습니다.

여기서 주의할 점은 data 변화가 감지되어 document.body.appendChild 가 매번 실행되는것이 아니라, Meteor.ui.render에 전달된 function 만 재실행되어 데이타가 변화되어 보입니다.

cursor.forEach

기본적으로 알고 있는 forEach와 동일한 기능입니다.

syntax

cursor.forEach(callback)

client / server 구분없음.

example

// Print the titles of the five top-scoring posts
var top_posts = Posts.find({}, {sort: {score: -1}, limit: 5});
var count = 0;
top_posts.forEach(function (post) {
  //
  // top_posts cursor로부터 forEach를 사용하여 접근가능한 post 를 컨트롤 합니다.
  //
  console.log("Title of post " + count + ": " + post.title);
  count += 1;
});

cursor.fetch

cursor에 포함되어 있는 데이타를 Array로 리턴합니다. 가장 많이 사용되는 operator입니다.

syntax

cursor.fetch()

client / server 구분없음.

example

var Users = new Meteor.Collection("users");          

if (Meteor.is_client) {                              
  var frag = Meteor.ui.render(function () {
    //
    // Meteor.ui.render 에 지정된 function은
    // reactivity context 입니다.
    //

    //
    // 그러므로, Users cursor에 데이타 변화가 있으면
    // 현재 context function은 재실행되어 집니다.
    //
    var a = Users.find().fetch();          

    //
    // 마지막 데이타의 num 필드값을 출력합니다.
    // 리턴값은 무조건 문자열이어야 합니다.
    //          
    return '' + (a.length ? a[a.length-1]['num']: '')
  });                                                

  Meteor.startup(function() {                    
    //
    // 마지막 데이타의 num 필드의 값이 변화되어
    // 화면에 표시됩니다.
    // 변화될때마다 append 되는것이 아닙니다.
    //    
    document.body.appendChild(frag);                 
  });                                                
}                                                    

client(firebug)에서 데이타를 입력해보겠습니다.

>>> Users.insert({num:4})
"b0bddb0d-8561-4b74-8cc9-9dd561b59f51"

>>> Users.insert({num:5})
"45230ef6-3f3f-4fe1-a995-fa7ddb1d2cf6"  

변화되는 갯수의 값이 화면에 표시될것입니다.

cursor.map

syntax

Array Users.find().map(callback);

client / server 구분없음.

example

var arr = Users.find().map(function(x) {
  //
  // 리턴할 값을 정합니다.
  // 
  return x.online_now ? x : -1
});
console.log(arr);

cursor.observe

cursor에 대해서 변화값을 모니터링하고, 각각의 CRUD 변화에 대한 callback function을 지정할 수 있습니다.

syntax

Object cursor.observe(callbacks)

client 에서만 가능합니다.

각 callback의 properties 설명입니다.

cursor.observe의 리턴값은 stop method 를 지원하는데, 이것을 사용하면 모니터링을 중지할 수 있습니다.

example

var Users = new Meteor.Collection('users');

var count = 0;

//
// name: ???
// admin: true
// online_new: true
//
var query = Users.find({admin: true, online_now: true});

//
// 위 query 를 모니터링 합니다.
//
var handle = query.observe({
  //
  // INESRT 발생시 callback
  //
  added: function (user) {
    count++;
    console.log(user.name + " brings the total to " + count + " admins.");
  },
  //
  // DELETE 발생시 callback
  //
  removed: function () {
    count--;
    console.log("Lost one. We're now down to " + count + " admins.");
  }
});

//
// observe 를 5초 뒤에 멈춥니다.
//
setTimeout(function () {handle.stop();}, 5000);

client(firebug)에서 테스트해보겠습니다.

//
// INSERT
//
>>> Users.insert({name: "nanhapark", admin:true, online_now: true});
nanhapark brings the total to 1 admins.
"3d391c39-1091-4990-9317-10e0974830ce"

//
// online_now 값을 false 으로 설정하니
// added callback 에서 지정한 console.log 내용이 보여지지 않습니다.
//    
>>> Users.insert({name: "nanhapark", admin:true, online_now: false});
"329ce5f2-045b-42c3-8d4e-21c99c425774"

//
// 모두 지우고, 남은 관리자는 0명
//
>>> Users.remove({})
Lost one. We're now down to 0 admins.

Conclusion

저번시간과 합쳐서 Collection과 Cursor 그리고, Access Operator에 대해서 알아보았습니다. 여러분은 CRUD를 할 수 있고, 이것의 변화는 reactivity context 와 관계 있다는것도 알게 되었습니다. Meteor Template 기능을 같이 사용하여 무언가를 만들 수 있을 것입니다. 다음 시간에는 Meteor의 컨셉이 뭔지, client/server 개념이 뭔지 그리고, 디렉토리 구성이 어떻게 되는지에 대한 기본적인 내용에 대해서 알아보겠습니다. 감사합니다.

추천 관련글