Mongoose で MongoDB の Embedded Documents の扱いで嵌まったこと

October 30, 2011

node(.js)と相性が良いということで、MongoDB とそのJavaScript O/R マッパーライクなモデリングライブラリの Mongoose を使い始めました。
MongoDBと言えばドキュメント指向モデルでそれを特徴づける Embedded Documents が有名ですが、この機能を Mongoose から利用する上で躓いたので、メモしておきます。

Embbed Document の Array について

var Users = new Schema({
name : String
});
var Comments = new Schema({
title : String
, body : String
, date : Date
});
var BlogPost = new Schema({
author : { type: ObjectId, ref: ‘User’ }
, title : String
, body : String
, date : Date
, comments : [Comments]
, meta : {
votes : Number
, favs : Number
}
});
mongoose.model(‘User’, Users);
mongoose.model(‘BlogPost’, BlogPost);

上記のような定義で、あるBlogPostのCommentsを追加して保存するときのコードは次のとおりになります。

BlogPost.findById(‘xxxx’, function(err, blogpost) {
var comment = { ‘title’: “タイトル”, ‘body’: “ボディ” };
blogpost.comments.push(comment);
 // comment.date = new Date();
blogpost.save(function(err) {});
});

ここでcommentオブジェクトをcommentsプロパティにpushしてるわけですが、上記のコメント行のように push 後にもとのオブジェクトにプロパティをセットしてもblogpostのcommentsプロパティの中身には反映されません。
Array 内のオブジェクトは参照を持っていると思っていると嵌まります。push メソッドであってもcommentsの中身はコピーされただけだと考えてないといけません。

ObjectID の等号比較

各ドキュメントモデルには _id という主キーのようなものが付きますが、これの比較を単純に等号比較してもうまくいきません。先ほどの例でBlogPostのauthorにはUserの_idがセットされるわけですが、下記のようなことができません。

User.findById(‘xxxx’, function(err, user) {
BlogPost.find({}, function(err, blogposts) {
blogposts.forEach(function(blogpost, array) {
if (blogpost.author === user._id) {
// 来ない
}
});
});
})

ObjectIdなのですが、その状態での比較がうまくいかないため、String に変換して比較する必要があるようです。

blogposts.forEach(function(blogpost, array) {
if (String(blogpost.author) === String(user._id)) {
// 来る
}
});

JavaScript MongoDB

tilfin freelance software engineer