Mục lục
Subdocument là một document được nhúng bên trong một document khác. Nghĩa là bạn có thể lồng bất cứ một schema này vào một schema khác.
Mongoose có 2 khái niệm về subdoccument: array subdocument và single nested.
// File mongoose.subdocument.js var childSchema = new mongoose.Schema({ name: 'string' }); var parentSchema = new mongoose.Schema({ // Array of subdocuments children: [childSchema], // Single nested subdocuments. Work với mongoose >= 4.2.0 child: childSchema });
Một subdocument hoàn toàn giống với document thông thường. Chúng cũng có các middleware, validation, virtuals etc. Một điểm khác biết lớn nhất là subdocument không được lưu riêng lẽ, chúng phải được lưu với document chứa nó(parent document).
// file mongoose.subdocument.js var Parent = mongoose.model('Parent', parentSchema); var parent = new Parent({ children: [{ name: 'Matt' }, { name: 'Sarah' }] }) parent.children[0].name = 'Matthew'; // `parent.children[0].save()`sẽ kích hoạt tricker middle parent.save(callback);
Subdocument hook
Như đã nói ở trên, subdocument cũng giống như một document bình thường. Nên chúng cũng sẽ có các hook trigger. Ví dụ như khi parent document save() thì hook trigger save() của subdocument cũng được gọi.
// File mongoose.subdocument.js childSchema.pre('save', function (next) { if ('invalid' == this.name) { return next(new Error('#sadpanda')); } next(); }); var parent = new Parent({ children: [{ name: 'invalid' }] }); parent.save(function (err) { console.log(err.message) // #sadpanda });
- MacOS: ./node_modules/.bin/babel-node mongoose.document.js
- Windows: .\node_modules\.bin\babel-node mongoose.document.js
Output: #sadpanda
Tìm kiếm subdocument trong document
Mặc định mỗi subdocument đều có _id. Mongoose document array( document có type array) có sẵn method id hỗ trợ tìm kiếm một subdocument theo _id.
var doc = parent.children.id(_id);
Thêm subdocument vào array
MongooseArray có các method như push, unshift, addToSet để thêm một subdocs vào array.
// File mongoose.subdocument.js var Parent = mongoose.model('Parent'); var parent = new Parent; // create a comment parent.children.push({ name: 'Liesl' }); var subdoc = parent.children[0]; console.log(subdoc) // { _id: '501d86090d371bab2c0341c5', name: 'Liesl' } subdoc.isNew; // true parent.save(function (err) { if (err) return handleError(err) console.log('Success!'); });
Run:
- MacOS: ./node_modules/.bin/babel-node mongoose.document.js
- Windows: .\node_modules\.bin\babel-node mongoose.document.js
Output: Success!
Xoá subdocumet
Mỗi subdocument đều có method remove() để xoá nó ra khởi array nếu nó là arraysubdoc, hoặc xoá nó ra khởi parent documet nếu single nested.
parent.children.id(_id).remove(); // Equivalent to `parent.child = null` parent.child.remove(); parent.save(function (err) { if (err) return handleError(err); console.log('the subdocs were removed'); });
Get Parent docuement từ subdocumet
Gọi parent() để lấy parent của subdocument.
// File mongoose.subdocument.js const getParentDoc = async () => { const doc = new Parent({ children: [{ name: 'foo' }], child: { name: 'bar' } }); console.log(doc) console.log(doc.child.parent() === doc); // true console.log(doc.children[0].parent() === doc); // true } getParentDoc();
Run:
- MacOS: ./node_modules/.bin/babel-node mongoose.document.js
- Windows: .\node_modules\.bin\babel-node mongoose.document.js
Output:
true
true
Nếu có nhiều subdocument lồng nhau, bạn có thể gọi ownerDocument() để lấy top-level document.
const schema = new Schema({ level1: new Schema({ level2: new Schema({ test: String }) }) }); const Model = mongoose.model('Test', schema); const doc = new Model({ level1: { level2: 'test' } }); doc.level1.level2.parent() === doc; // false doc.level1.level2.parent() === doc.level1; // true doc.level1.level2.ownerDocument() === doc; // true
Kết
Them mình nghĩ subdocument khá giống với quan hệ (one – to – one, one – to – many) trong cơ sở dữ liệu quan hệ. Array subdocument tương ứng one – to – many và single nested là one – to one.