Skip to content

Understanding Document Updates

Unlike deletion, which is a swift “find it and kill it” operation, updating a document requires a slightly different approach.

Mongoose does have direct update methods (like findByIdAndUpdate), but for the vast majority of application logic, the cleanest and safest pattern is Load → Modify → Save.

When we use the “Load → Modify → Save” pattern, we bring the document into our Node.js memory, alter its properties using standard JavaScript, and then tell Mongoose to persist those changes back to the database.

  1. Load: const doc = await Model.findById(id);
  2. Modify: doc.property = newValue;
  3. Save: await doc.save();

This pattern is incredibly powerful because calling .save() triggers all of our Mongoose Schema validations and middleware hooks (which we will learn about later). If we bypass .save() and use direct update queries, Mongoose might not catch invalid data before it hits the database.

// The conceptual update pattern
async function toggleActiveStatus(userId) {
// 1. Load
const user = await User.findById(userId);
// Guard clause against nulls
if (!user) return null;
// 2. Modify (just normal JavaScript assignment)
user.isActive = !user.isActive;
// 3. Save (Schema validation happens right here!)
await user.save();
return user;
}

Treat findByIdAndUpdate() as a specialty tool for bulk operations or highly un-orchestrated atomic updates. For user-driven data modifications, stick to the save() flow to ensure your Schema rules are respected.

A Neon-Retro themed technical flow diagram illustrating the 3-step 'Load, Modify, Save' pattern: Data fetching from MongoDB, in-memory JavaScript modification, and a Validation Checkpoint before saving.

Mongoose Docs: Updating Documents


Let’s put this pattern to work immediately by building a “Mark as Read” feature for our contact submissions.