Mongoose Model Relationships

In Mongo there are two ways to modeling related data, and we can use both in Mongoose:

  • via embedding
  • via referencing (linking)

Sub-documents (MongoDB embedded documents)

Sub-documents are just what they sound like: documents with their own schemas nested in other documents. They take of the form of objects within an array. You can think of this as a sort of has_many relationship - the context to use embedded documents is data entities need to be used/viewed in context of another.

Let's look at these two schemas below - we can embed childSchema into the property children:

const childSchema = new mongoose.Schema({ name: 'string' });

const parentSchema = new mongoose.Schema({
  children: [childSchema]
});

const Parent = mongoose.model('Parent', parentSchema);

Parent.create({ children: [
  { name: 'Matt' },
  { name: 'Sarah' }
]}, function(err, parent) {
  if (err) {
    console.log(err);
    return;
  }
  console.log(parent);
});

Finding a sub-document

All documents in Mongoose have an _id, including sub-documents. Using the example above, we can find a specific sub-document from the array by using the .id function on the key we want to search.

// in our first example, this should return one of the sub-documents
const doc = parent.children.id(idYouAreLookingFor);

Adding and Removing sub-documents

Mongoose sub-document collections are arrays, and therefore contain methods like as .push(), .pop(), and .unshift().

parent.children.push({ name: 'Ester' }); // pushes Ester
parent.children.pop(); // pops Ester

Note that these functions don't save the instance, so you'll need to call .save() manually afterwards.

Population (MongoDB document references)

Storing references to other documents involves defining a specific model to reference, as well as the type of what's being stored. For example, referring to a User in a Book model would involve referencing the User model, as well as storing the user's ObjectId.

const Schema = mongoose.Schema;

const bookSchema = Schema({
  author: { type: Schema.Types.ObjectId, ref: 'User' },
  title: String
});

const Book = mongoose.model('Book', bookSchema);

// creating a book and storing an author's id
Book.create({ title: 'Fahrenheit 451', author: author._id }, function(err, book) {
  // access book here
});

However, if we query for a book, the author's information won't automatically populate. The query would give back the ObjectId only! In order to populate the model's data, we can use the .populate() function after the query, as well as use .exec() to execute the callback function.

Book.findOne({ title: 'Fahrenheit 451' })
.populate('author')
.exec(function(err, book) {
  // access book with author data here
});

results matching ""

    No results matching ""