mongooseで埋め込みを使う
MongoDBのリレーションでやるか埋め込みでやるか迷った末に埋め込みでやることにしたので、
mongooseでのやり方をざっと試してみた。
使ったバージョン
node.js v0.8.18
mongoose 3.5.5
試験ソース
コールバックだらけになるので、jsdeferred使って流れ整理した。
var Deferred = require('./deps/jsdeferred').Deferred, // mongoose mongoose = require('mongoose'), // 子スキーマ ChildSchema = new mongoose.Schema({ name : String }), // 親スキーマ ParentSchema = new mongoose.Schema({ name : String, childlen : [ChildSchema] }), // 親モデル Parent = mongoose.model('Parent', ParentSchema); // 接続 mongoose.connect('mongodb://localhost/foo'); !function() { // 最初にdb.parentsを全部消しておく var d = new Deferred(); Parent.remove(function(err) { if (err) { d.fail(err); return; } d.call(); }); return d; }() .next(function() { var d = new Deferred(), // parentを新規作成して保存 parent = new Parent({ name : 'test' }); parent.save(function(err) { if (err) { d.fail(err); return; } d.call(); }); return d; }) .next(function() { var d = new Deferred(); // 親を取得 Parent.findOne({ name : 'test'}, function(err, parent) { if (err) { d.fail(err); return; } // 親の名前をチェック console.log(parent.name); console.log('子供が0人'); // この時点ではまだ子供がいない console.log(parent.childlen); // 子供を一人追加 parent.childlen.push({ name : 'baby1' }); parent.save(function(err) { if (err) { d.fail(err); } d.call(); }); }); return d; }) .next(function() { var d = new Deferred(); // 親を取得 Parent.findOne({ name : 'test'}, function(err, parent) { if (err) { d.fail(err); return; } console.log('子供が1人'); console.log(parent.childlen); // まとめて複数人追加 parent.childlen.push({ name : 'baby2' }); parent.childlen.push({ name : 'baby3' }); parent.childlen.push({ name : 'baby4' }); parent.save(function(err) { if (err) { d.fail(err); } d.call(); }); }); return d; }) .next(function() { var d = new Deferred(); // 親を取得 Parent.findOne({ name : 'test'}, function(err, parent) { if (err) { d.fail(err); return; } console.log('子供が4人'); console.log(parent.childlen); // 名前を更新する parent.childlen[0].name = 'John'; parent.childlen[1].name = 'Paul'; parent.childlen[2].name = 'George'; parent.childlen[3].name = 'Ringo'; parent.save(function(err) { if (err) { d.fail(err); } d.call(); }); }); return d; }) .next(function() { var d = new Deferred(); // 親を取得 Parent.findOne({ name : 'test'}, function(err, parent) { if (err) { d.fail(err); return; } console.log('更新後'); console.log(parent.childlen); // 1つ削除 parent.childlen.remove(parent.childlen[1]); parent.save(function(err) { if (err) { d.fail(err); } d.call(); }); }); return d; }) .next(function() { var d = new Deferred(); // 親を取得 Parent.findOne({ name : 'test'}, function(err, parent) { if (err) { d.fail(err); return; } console.log('1件削除後'); console.log(parent.childlen); // 全て削除する /** * forEachだとうまく消せない */ // parent.childlen.forEach(function(c) { // c.remove(); // }); var i, len = parent.childlen.length; for (i = len - 1; i >= 0; i--) { parent.childlen[i].remove(); } parent.save(function(err) { if (err) { d.fail(err); } d.call(); }); }); return d; }) .next(function() { var d = new Deferred(); // 親を取得 Parent.findOne({ name : 'test'}, function(err, parent) { if (err) { d.fail(err); return; } console.log('0人'); console.log(parent.childlen); d.call(); }); return d; }) .next(function() { mongoose.disconnect(); }) .error(function(err) { console.log(err); mongoose.disconnect(); });
実行結果
$ node index test 子供が0人 [] 子供が1人 [{ name: 'baby1', _id: 51110eba0d42bc5711000003 }] 子供が4人 [{ name: 'baby1', _id: 51110eba0d42bc5711000003 } { name: 'baby2', _id: 51110eba0d42bc5711000004 } { name: 'baby3', _id: 51110eba0d42bc5711000005 } { name: 'baby4', _id: 51110eba0d42bc5711000006 }] 更新後 [{ _id: 51110eba0d42bc5711000003, name: 'John' } { _id: 51110eba0d42bc5711000004, name: 'Paul' } { _id: 51110eba0d42bc5711000005, name: 'George' } { _id: 51110eba0d42bc5711000006, name: 'Ringo' }] 1件削除後 [{ _id: 51110eba0d42bc5711000003, name: 'John' } { _id: 51110eba0d42bc5711000005, name: 'George' } { _id: 51110eba0d42bc5711000006, name: 'Ringo' }] 0人 []
感想
削除の時にforEachで回すとインデックスの関係か削除うまくいかないみたい。