[cookbook] Meteor Collection #1 (Model 이제 별거 아니다.)

Meteor Collection #1 Introduction

Meteor Collection이란 데이타를 저장하는 곳을 말합니다. 이는 MongoDB에서 사용되는 용어이며, 일반 DB에서 table 이라고 생각하시면 됩니다. 참고로 Meteor 에서 db 명은 meteor 입니다.

첫번째 시간으로 collection에 대해서 맛만 보겠습니다.

collection_stamp

collection_stamp

Feature

Collection TroubleShooting

이건 알고 넘어가야 합니다. Meteor 문서에는 언급조차 안되어 있기 때문입니다. Collection 을 생성하는 부분에 대한 내용입니다.

insert failed: 404 -- Method not found

client에서 collection생성하여 insert 했는데 에러난 경우입니다. 이는 collection.insert 문서에서 anywhere 사용가능하다고 했으나, 어디에도 해당 에러에 대한 언급은 없습니다. 제가 내린 결론은 CRUD 는 client에서 가능하나, collection의 생성은 안전하게 server 에서만 허용되는거라 생각됩니다. 보안상 이슈가 될 수도 있으니까요 :-) 아래 client(firebug)에서 명령한 연습코드 보시죠.

//
// 아무런 에러없이 떨어집니다.
//
>>> foo = new Meteor.Collection("foo");
Object { _manager={...}, _driver={...}, _collection={...}, more...}

//
// 이때 에러가 납니다. 404
// 참고로 해당 명령은 mongodb에 collection을 생성하는 역할을 합니다.
//    
>>> foo.insert({user_id: "nanhapark"});
"7928a897-e882-4783-9b12-ecddc18e6b05"
POST http://localhost:3000/sockjs/460/t6kp09x_/xhr_send
204 No Content    41ms  sockjs...fc3aa35 (788째 줄)

insert failed: 404 -- Method not found

이것의 해결방법은 이렇습니다.

collection은 사용되기 전에 client 혹은 server 코드에 collection 객체가 생성되어야 합니다.

//
// 이와 같이 생성해놓으면
// client(firebug) 에서 CRUD 적용을 할 수 있습니다.
//
foo = new Meteor.Collection("chatrooms");

if (Meteor.is_client) {                        
}                                              

if (Meteor.is_server) {                        
}                                              

new Meteor.Collection

data store에 collection을 생성하도록 초기화하는 API입니다. 이것은 collection을 생성하지는 않습니다.

Syntax

new Meteor.Collection(name, manager)

client / sever 어디서나 사용가능

Anywhere 사용가능하나 이건 잘못된 것. collection을 client/server 구분없이 아무곳에서나 생성하는 것은 보안상 이슈로 server 측에서만 가능합니다. 위에 troubleshooting 보시면 됩니다.

collection name null ?

Collection name 을 입력하지 않으면 어떤 결과가 나오는지 분석해드리겠습니다. javascript 파일에 아래와 같이 기입합니다.

//
// name null
//
Chatrooms = new Meteor.Collection();

if (Meteor.is_client) {             
}                                   

if (Meteor.is_server) {             
}                                   

브라우져에서 실행하는 즉시 client(firebug) console에는 아래와 같은 메세지가 보여집니다.

Warning: creating anonymous collection. It will not be saved or synchronized over the network. (Pass null for the collection name to turn off this warning.)

익명의 collection, db에 저장되지 않는다고 하네요. 즉, 테스트할 수 있는 공간을 내부 hash로 관리해줍니다.

>>> Chatrooms.insert({num:1})
"de006c17-1f03-4a8f-8a20-fd93cd442177"

//
// 데이타가 들어가네요.
//
>>> Chatrooms.find().fetch()
[Object { num=1,  _id="de006c17-1f03-4a8f-8a20-fd93cd442177"}]

하지만, mongodb에는 저장되지 않는군요.

//
// 기존 테스트한 데이타만 있군요.
//
> db.chatrooms.find()                                                
{ "_id" : "d80b0fc6-b471-403e-8054-e7fa75d53707", "user_id" : "cha" }

example

기본적인 CRUD 예제입니다.

//
// 1. Session 에서 my_user_id 값을 가져오는군요. 로그인된 상태인가 봅니다.
// 2. find 하여 cursor 를 가져오고
// 3. 실제 데이타에 접근하기 위하여 fetch 를 사용하여
// 4. my_messages 에 배열값을 저장합니다.
//
var my_messages = Messages.find({user_id:Session.get('my_user_id')}).fetch();

//
// 데이타를 넣는군요.
//
Messages.insert({text: "Hello, world!"});

//
// important 필드를 true 값으로 추가합니다.
// 문서에는 my_messages[0]._id 이 my_messages[0].id 으로 되어 있다는것에 유의하세요.
//
Messages.update(my_messages[0]._id, {$set: {important: true}});

collection.find

원하는 데이타를 collection에서 찾아주는 API 입니다.

syntax

collection.find(selector, [options]) Anywhere

selector 부분은 MongoDB의 selector를 아셔야 합니다.

Meteor와 Mongodb와 혼돈하지 마세요

Meteor에서 사용하는 data store가 mongodb 입니다. 하지만, Model에서 지원하는 operator들이 mongodb와 동일하지는 않고, 다만 MongoDB Style 이라는 것입니다.

아래내용은 mongodb 에 붙어서 meteor api를 사용한 내용입니다.

//
// 에러가 보입니다.
//
> db.col.find({}, {sort: {num:-1}})                                      
error: { "$err" : "Unsupported projection option: num", "code" : 13097 } 

MongoDB에서는 sort operator가 존재하여, 위와 같이 사용할 수 없습니다.

//
// 이와 같이 sort operator를 chaining 하여 사용해야 합니다.
//
> db.col.find().sort({num:1})                                            
{ "_id" : ObjectId("502e3ba5a924cea10485e4eb"), "num" : 1 }              
{ "_id" : ObjectId("502e3ba7a924cea10485e4ec"), "num" : 2 }              
{ "_id" : ObjectId("502e3ba8a924cea10485e4ed"), "num" : 3 }              

아래 내용은 client(firebug)에서 요청한 내용입니다.

>>> col.find({}, {sort: {num:-1}}).fetch()
[Object { _id="502e3ba8a924cea10485e4ed",  num=3}, Object { _id="502e3ba7a924cea10485e4ec",  num=2}, Object { _id="502e3ba5a924cea10485e4eb",  num=1}]

>>> col.find({}, {skip: 1, sort: {num:-1}}).fetch()
[Object { _id="502e3ba7a924cea10485e4ec",  num=2}, Object { _id="502e3ba5a924cea10485e4eb",  num=1}]

Conclusion

제가 사용해본 결과 Model을 javascript에서 이렇게 손쉽게 다룰 수 있다는것에 대해서 굉장히 놀랬습니다. Backbone.js를 좋아하는 저의 입장에서는 Model을 Backend와 연동할 때 그 불편함이 당연하다 싶었는데, 그것을 당연하다고 생각한것이 후회가 될 정도였습니다. 그럼 다음시간에는 collection의 나머지 부분들을 알아보겠습니다. 감사합니다.

추천 관련글