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)) { // 来る } });