Sling Academy
Home/Node.js/Mongoose: How to find and update subdocuments

Mongoose: How to find and update subdocuments

Last updated: December 31, 2023

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.

Next Article: Grouping Results in Mongoose (with examples)

Previous Article: Mongoose: Retrieving the Latest Document

Series: Mongoose.js Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates