Mongoose: How to find and update subdocuments

Updated: December 31, 2023 By: Guest Contributor Post a comment

Mongoose is a powerful ODM library for MongoDB and Node.js that provides a higher level of abstraction, making database interactions easier and more secure. Handling subdocuments effectively is critical for achieving complex data management operations.

Understanding Subdocuments

Subdocuments in Mongoose are documents that are nested within other documents. They can be used to create complex data models with nested structures. Here’s how to define a schema with subdocuments:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const childSchema = new Schema({ name: String });
const parentSchema = new Schema({
  children: [childSchema]
});

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

Finding Subdocuments

Finding subdocuments requires querying the parent document and then filtering through its children. Here’s how it’s typically done:

Parent.findOne({ 'children.name': 'John Doe' }, (err, doc) => {
  if (err) return handleError(err);
  const child = doc.children.find(c => c.name === 'John Doe');
  console.log(child);
});

Updating Subdocuments

Updating subdocuments can be done using the Mongoose’s array update operators. Here’s an example that updates a subdocument:</p

Parent.findOne({ 'children._id': childId }, (err, doc) => {
  if (err) return handleError(err);
  const child = doc.children.id(childId);
  child.name = 'Jane Doe';
  doc.save();
});

Advanced Subdocument Operations

For more complex operations like atomic updates and subdocument validation, you will need a deeper understanding of Mongoose array updating methods and middleware.

Atomic Updates on Subdocuments

Below is an example of how to perform an atomic update using `findOneAndUpdate` method on a subdocument:

Parent.findOneAndUpdate(
  { 'children._id': childId },
  { '$set': { 'children.$.name': 'Jane Smith' } },
  { new: true },
  (err, doc) => {
    if (err) return handleError(err);
    // document after the update
    console.log(doc);
  }
);

Subdocument Validation

Subdocument validation is crucial. Here’s an example to ensure your subdocuments are validated:

childSchema.pre('save', function (next) {
  if ('invalid' == this.name) {
    next(new Error('#validation failed'));
  } else {
    next();
  }
});

Collation and Subdocument Queries

Working with different languages and character sets requires proper collation. Querying subdocuments considering collation can be done as shown below:

Parent.find()
  .collation({ locale: 'en', strength: 2 })
  .find({ 'children.name': 'Jöhn Döe' })
  .exec((err, docs) => {
    // Handle the found documents
  });

Performance Considerations

Performance is critical when finding and updating subdocuments. Here are some tips to optimize your queries:

  • Use indexing properly.
  • Avoid fetching unnecessary data by projection.
  • Always update in bulk when possible.

Conclusion

In this article, we’ve explored various techniques for finding and updating subdocuments in Mongoose. With a combination of querying strategy and the use of subdocument specific methods, you can manage subdocuments effectively in your applications.