mongoose 에서의 virtual model 에 대해서 알아보자.


virtual model 이란 collection에 정의 되지 않은 filed 이지만 정의된 field 처럼 사용할 수 있게 하는 기능이다. 


예를 들어

다음과 같이 스키마를 정의하고 모델을 만들어보자.


var personSchema = new
 Schema({
  name: {
    first: String,
    last: String
  }
});

// compile our model
var Person = mongoose.model('Person', personSchema);

// create a document
var bad = new Person({
    name: { first: 'Walter', last: 'White' }
});


그 모델에 따라 document를 만들게 된다. 

그렇다면 이 도큐먼트에서 참조할 수 있는 key는 schema를 정의할 때 정의한 key 밖에 없지만,

virtual을 이용하게 되면? virtual key를 이용해 schema에 포함되지 않을 키를 설정하고 구미에 맞게 function을 통해 다양한 활용이 가능하게 된다.


다음과 같이 virtual을 쓴다. 이렇게 virtual 메소드를 써서 새로운 키 name.full을 쓸 수 있게 된다. 


personSchema.virtual('name.full').get(function () {
  return this.name.first + ' ' + this.name.last;
});




Now, when we access our virtual "name.full" property, our getter function will be invoked and the value returned:


console.log('%s is insane', bad.name.full); // Walter White is insane


virtual 에는 setter 기능도 있는데, 다음과 같이 정의하면 된다.


bad.name.full = 'Breaking Bad';



Mongoose lets you do this as well through its virtual property setters:



personSchema.virtual('name.full').set(function (name) {
  var split = name.split(' ');
  this.name.first = split[0];
  this.name.last = split[1];
});

...

mad.name.full = 'Breaking Bad';
console.log(mad.name.first); // Breaking
console.log(mad.name.last);  // Bad

'데이터베이스 > mongodb' 카테고리의 다른 글

mongoose static method vs instance method  (0) 2015.02.11
node.js mongoose에서의 virtual model  (0) 2015.02.10
mongodb에서의 join  (1) 2015.02.10
mongodb modeling  (0) 2015.02.09
블로그 이미지

종환 Revolutionist-JongHwan

github.com/alciakng 항상 겸손하자.

댓글을 달아 주세요

mongodb는 nosql이다. no sql이 아닌 not only sql 이다.

sql 처럼 테이블 조인을 할 수는 없지만 이와 비슷한 기능을 제공해 준다.


바로 collection간의 population이라는 기능이다. 


There are no joins in MongoDB but sometimes we still want references to documents in other collections. This is where population comes in.

Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). We may populate a single document, multiple documents, plain object, multiple plain objects, or all objects returned from a query. Let's look at some examples.


var mongoose = require('mongoose')
  , Schema = mongoose.Schema
  
var personSchema = Schema({
  _id     : Number,
  name    : String,
  age     : Number,
  stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

var storySchema = Schema({
  _creator : { type: Number, ref: 'Person' },
  title    : String,
  fans     : [{ type: Number, ref: 'Person' }]
});

var Story  = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);




위와 같이 두개의 collection을 정의하여 놓는다.

psersonSchema는 stroySchema를 embedding하고 있다. 

즉 일대다 관계이다. storySchema도 역시 personSchema를 참조하고 있다. 

이 경우에 population을 구현해보자.

우선 새로운 document를 만들고 이를 save하면서 stroy document도 save한다. 



var aaron = new Person({ _id: 0, name: 'Aaron', age: 100 });

aaron.save(function (err) {
  if (err) return handleError(err);
  
  var story1 = new Story({
    title: "Once upon a timex.",
    _creator: aaron._id    // assign the _id from the person
  });
  
  story1.save(function (err) {
   
 if (err) return handleError(err);
    // thats it!
  });
})




그리고 다음과 같이 stroy collection에서 population을 구현할 수 있다.

_creator를 populating 함으로써 person객체를 받아와 객체안의 이름을 populating 하고 있는 것이다.



Story
.findOne({ title: 'Once upon a timex.' })
.populate('_creator')
.exec(function (err, story) {
  if (err) return handleError(err);
  console.log('The creator is %s', story._creator.name);
  // prints "The creator is Aaron"
})



'데이터베이스 > mongodb' 카테고리의 다른 글

mongoose static method vs instance method  (0) 2015.02.11
node.js mongoose에서의 virtual model  (0) 2015.02.10
mongodb에서의 join  (1) 2015.02.10
mongodb modeling  (0) 2015.02.09
블로그 이미지

종환 Revolutionist-JongHwan

github.com/alciakng 항상 겸손하자.

댓글을 달아 주세요

지금 껏 나는 express의 본질인 connect middleware에 대해서 정확하게 이해하지 못하고 node.js를 사용해 온 것 같다.

미들웨어를 잘 설명하는 답변을 찾아 포스팅한다.

In most frameworks you get a request and you want to return a response. Because of the async nature of Node.js you run into problems with nested call backs if you are doing non trivial stuff. To keep this from happening Connect.js (Express.js is a layer on top of connect) has something that is called middleware which is a function with 2, 3 or 4 parameters.

대부분의 프레임워크에서는 request와 response가 있다. node.js의 비동기적인 특성 때문에 nested callback 문제에 부딪힐 수 있다(정확히 무슨말인지 이해가 안감)..

이를 위해서 Express는 미들웨어를 제공한다..

function (<err>, req, res, next) {}

Your Express.js app is a stack of these functions.

enter image description here

위의 그림이 명쾌하게 설명해주고 있다. request가 들어오면 built-in middleware가 실행되고(express는 네가지 미들웨어를 가진다. 

 

그 다음 router middleware가 실행된다. 이 시점에서 stack 에 있는 여러 routing function을 실행할 수 있다.  이렇게 한 스택에 있는 function을 사용하기 위해서 사용되는 메소드가 next()이다. 

The router is special, it's middleware that lets you execute one or more middleware for a certain url. So it's a stack inside a stack.

router는 특별하다. 그 것은 특정한 url에 들어온 요청을 한개이상의  middleware를 써서 실행하게 도와준다.  그렇기 때문에 stack안의 stack구조를 갖게된다.

So what does next do? Simple, it tells your app to run the next middleware. But what happens when you pass something to next? Express will abort the current stack and will run all the middleware that has 4 parameters.

그렇다면 next가 하는 역할은 무엇일까? 

expressjs 공식홈에 자세한 설명이 나와있다.


Middleware is a function with access to the request object (req), the response object (res), and the next middleware in line in the request-response cycle of an Express application, commonly denoted by a variable named next. Middleware can:

  • Execute any code.
  • Make changes to the request and the response objects.
  • End the request-response cycle.
  • Call the next middleware in the stack.

If the current middleware does not end the request-response cycle, it must call next() to pass control to the next middleware, otherwise the request will be left hanging.

하나의 미들웨어는 request object 와 response object에 접근하는 function이다. req-res 사이클에서 next 미들웨어에도 접근할 수 있다. 이렇게 한 스택안에 여러가지의 routing middleware가 있을 때 next middleware에 접근할 수 있는 function이 next()이다... 

그렇다면 응용 예를 하나 보겠다.

app.param() 메소드를 통한 응용인데 ...

app.param()은 공식홈에서 이렇게 가이드를 하고 있다.

Add callback triggers to route paramters, where name is the name of the parameter or an array of them, and function is the callback function. The parameters of the callback function are the request object, the response object, the next middleware, and the value of the parameter, in that order.

For example, when :user is present in a route path, you may map user loadig logic to automatically provide req.user to the route, or perform validations on the parameter input.

첫번째 인자에 parameter를 주는데 이 파라미터가 next를 통해 다음 미들웨어를 호출할때 index로 쓰인다. 무슨 말인고 하면, 아래와 같이 app.param('user' 라고 user 파라미터를 주었다면 next를 통해 다음 라우팅 미들웨어를 실행할 때 user파라미터를 가지는 middleware가 실행되는 것이다.

app.param('user', function(req, res, next, id) {

  // try to get the user details from the User model and attach it to the request object
  User.find(id, function(err, user) {
    if (err) {
      next(err);
    } else if (user) {
      req.user = user;
      next();
    } else {
      next(new Error('failed to load user'));
    }
  });
});


따라서 아래와 같이 응용을 할 수 있게 되는데,  param을 통해 load 미들웨어를 실행하고 id를 파라미터로 가지는 미들웨어를 next()를 통해 선택적으로 실행한다. 즉 id 파라미터를 가지는 url로 들어오는 모든 요청은 aritcles.load 미들웨어를 거쳐 실행된다. 


app.param('id', articles.load); app.get('/articles', articles.index); app.get('/articles/new', auth.requiresLogin, articles.new); app.post('/articles', auth.requiresLogin, articles.create); app.get('/articles/:id', articles.show); app.get('/articles/:id/edit', articleAuth, articles.edit); app.put('/articles/:id', articleAuth, articles.update); app.delete('/articles/:id', articleAuth, articles.destroy);






블로그 이미지

종환 Revolutionist-JongHwan

github.com/alciakng 항상 겸손하자.

댓글을 달아 주세요