목요일, 1월 8

mongoose 간단 예제와 methods, statics 활용 차이



 sql 데이터베이스 환경을 편하게 사용하기 위해서 ORM과 같은 개념이 등장했습니다. 그리고 보통 사람들은 ORM이 제공하는 기능에 추가로 메소드와 sql 쿼리를 매칭시켜 사용하였습니다.

mongo와 같은 NoSQL에서는 이와 같은 개념을 ODM이라고 부릅니다.
mongoose는 대표적인 ODM 프레임워크 입니다.


mongoose에서는 document mapper를 클래스처럼 사용할 수 있는 기능을 제공하는데 클래스에서 사용하는 method를 정의해서 사용할 수 있습니다.

예를들어
var userSchema = mongoose.Schema({
        username        : String,        password        : String,        email           : String
});
module.exports = mongoose.model('User', userSchema);


위와 같은 사용자 스키마를 정의하면 몽구스는 해당 스키마를 도큐먼트로 매핑해서 사용할 수 있습니다.

먼저 정의한 스키마를 불러오고
var userModel   = require('./models/user');

새 ODM을 만듭니다.
var exampleUser = { username:'example'    , password: 'example'    , email: 'example@example.com'};
var newUser = new userModel(exampleUser);

이런 식으로 클래스 생성자처럼 사용할 수도 있고,
(내부적으론 매핑을 합니다.)

var newUser = new userModel();newUser.username    = 'example';newUser.password    = 'example';newUser.email       = 'example@example.com';

와 같이 직접 값을 넣어줄 수도 있습니다.


이런 식으로 클래스 객체처럼 모델을 다루게 되면, 클래스에 변수와 메소드처럼 모델을 사용하고 싶어집니다. 몽구스에서는 아주 쉽게 이런 작업을 할 수 있습니다.

// generating a hashuserSchema.methods.generateHash = function(password) {
    return bcrypt.hashSync(password, bcrypt.genSaltSync(10));};
// checking if password is validuserSchema.methods.validPassword = function(password) {
    return bcrypt.compareSync(password, this.local.password);};

이렇게 내부 메소드로 지정해놓으면,
var newUser = new userModel();newUser.username    = 'example';newUser.password    = newUser.generateHash('example');newUser.email       = 'example@example.com';

이렇게 사용할 수 있습니다.

이와 같이 사용할 수 있는 키워드로는 'methods' 와 'statics'이 있습니다.
http://mongoosejs.com/docs/2.7.x/docs/methods-statics.html


그럼 이제 이 글의 주제인 methods, 와 statics의 활용 차이를 살펴보겠습니다.
methods와 statics는 거의 동일한 역할을 합니다.

차이점은 자바와 같은 클래스의 일반 method와 static메소드의 차이와 동일합니다.

// generating a hashuserSchema.methods.generateHash = function(password) {
    return bcrypt.hashSync(password, bcrypt.genSaltSync(10));};
// generating a hashuserSchema.statics.generateHash = function(password) {
    return bcrypt.hashSync(password, bcrypt.genSaltSync(10));};

methods로 선언된 경우와 statics로 선언된 경우,

methods를 사용할 때는 요렇게 해야되고
var newUser = new userModel();newUser.local.username    = 'example';
newUser.local.password    = newUser.generateHash('example');
newUser.local.email       = 'example@example.com';


statics로 사용할 때는
var newUser = new userModel();newUser.username    = 'example';
newUser.password    = userModel.generateHash('example');
newUser.email       = 'example@example.com';
요렇게 해야합니다.


그러므로 methods는 새로 만든 객체를 통해 작업을 할 경우 선언해 사용하고, statics는 객체 선언이나 데이터 대입 없이 조회와 같은 기능을 선언해 사용하면 됩니다.


예를들어,
// create the uservar newUser            = new User();
newUser.username = username;newUser.email    = email;newUser.password = newUser.generateHash(password);
newUser.save(function(err) {
    if (err)
        return done(err);
    return done(null, newUser);});

위 예제에서 새 사용자를 저장하기 전에 패스워드 해쉬를 만드는 작업을 하게 되는데, 이와 같은 작업을 모델에 붙혀 재사용성을 높힐 수 있습니다.

userSchema.methods.addNewUser = function(callback) {
    this.password = this.generateHash(this.password);
    return this.save(callback);}
대충 이런식이죠.


statics의 경우 사용자 조회와 같은 작업을 정의해두고 할 수 있겠죠.
userSchema.statics.findUser = function(id, callback) {
    return this.findOne({ uesrname : id }, callback);}


마무리하며,
mongoose는 스키마를 몽고디비 콜렉션과 매치시켜주는 매퍼입니다.
단순 매퍼 뿐 아니라 기능을 추가해서 사용할 수 있는데, methods와 statics가 있습니다.

methods는 하나의 자료(도큐먼트) 단위로 사용하는 기능.
statics는 하나의 콜렉션(스키마) 단위로 사용하는 기능.