Sub Docs

Sub-documents are docs with schemas of their own which are elements of a parents document array:

  1. var childSchema = new Schema({ name: 'string' });
  2. var parentSchema = new Schema({
  3. children: [childSchema]
  4. })

Sub-documents enjoy all the same features as normal documents. The only difference is that they are not saved individually, they are saved whenever their top-level parent document is saved.

  1. var Parent = mongoose.model('Parent', parentSchema);
  2. var parent = new Parent({ children: [{ name: 'Matt' }, { name: 'Sarah' }] })
  3. parent.children[0].name = 'Matthew';
  4. parent.save(callback);

If an error occurs in a sub-documents’ middleware, it is bubbled up to the save() callback of the parent, so error handling is a snap!

  1. childSchema.pre('save', function (next) {
  2. if ('invalid' == this.name) return next(new Error('#sadpanda'));
  3. next();
  4. });
  5. var parent = new Parent({ children: [{ name: 'invalid' }] });
  6. parent.save(function (err) {
  7. console.log(err.message) // #sadpanda
  8. })

Finding a sub-document

Each document has an _id. DocumentArrays have a special id method for looking up a document by its _id.

  1. var doc = parent.children.id(id);

Adding sub-docs

MongooseArray methods such as push, unshift, addToSet, and others cast arguments to their proper types transparently:

  1. var Parent = mongoose.model('Parent');
  2. var parent = new Parent;
  3. // create a comment
  4. parent.children.push({ name: 'Liesl' });
  5. var subdoc = parent.children[0];
  6. console.log(subdoc) // { _id: '501d86090d371bab2c0341c5', name: 'Liesl' }
  7. subdoc.isNew; // true
  8. parent.save(function (err) {
  9. if (err) return handleError(err)
  10. console.log('Success!');
  11. });

Sub-docs may also be created without adding them to the array by using the create method of MongooseArrays.

  1. var newdoc = parent.children.create({ name: 'Aaron' });

Removing docs

Each sub-document has it’s own remove method.

  1. var doc = parent.children.id(id).remove();
  2. parent.save(function (err) {
  3. if (err) return handleError(err);
  4. console.log('the sub-doc was removed')
  5. });

Alternate declaration syntax

New in v3 If you don’t need access to the sub-document schema instance, you may also declare sub-docs by simply passing an object literal:

  1. var parentSchema = new Schema({
  2. children: [{ name: 'string' }]
  3. })

Next Up

Now that we’ve covered Sub-documents, let’s take a look at querying.