Update Operators and Upsert

Introduction

Updates modify existing documents without replacing the whole record unless you choose to. MongoDB provides updateOne, updateMany, and replaceOne, plus operators like $set, $inc, and $push. This chapter covers partial updates, array changes, upsert, and atomic findOneAndUpdate.

Prerequisites

updateOne and updateMany

Filter + update document:

javascript
// Set fields — $set required for partial update
db.posts.updateOne(
  { slug: "mongodb-basics" },
  { $set: { published: true, updatedAt: new Date() } }
)
 
// Update all matching
db.posts.updateMany(
  { published: false },
  { $set: { status: "archived" } }
)

Return document (requires returnDocument in drivers; mongosh shows):

javascript
const result = db.posts.updateOne(
  { slug: "draft-notes" },
  { $set: { published: true } }
)
// result.matchedCount, result.modifiedCount

Warning

Always Use Update Operators

updateOne(filter, { published: true }) replaces the entire document structure incorrectly in older patterns. Always use $set, $inc, etc.

Common Update Operators

Array Update Operators

$push with $each, $slice, $sort caps array size (subset pattern preview).

replaceOne

Replace entire document except _id:

javascript
db.posts.replaceOne(
  { slug: "draft-notes" },
  {
    title: "Rewritten Draft",
    slug: "draft-notes",
    published: false,
    body: "New content only.",
    createdAt: new Date()
  }
)

Dropped fields not in replacement are removed—prefer $set for partial edits.

Upsert

Insert if no match:

javascript
db.posts.updateOne(
  { slug: "new-post" },
  {
    $set: {
      title: "New Post",
      published: false,
      createdAt: new Date()
    }
  },
  { upsert: true }
)

upsertedId in result when insert occurred.

Use upsert for idempotent "create or update" by business key (slug, sku).

findOneAndUpdate

Atomic read-modify-write:

javascript
db.posts.findOneAndUpdate(
  { slug: "mongodb-basics" },
  { $inc: { viewCount: 1 } },
  { returnDocument: "after" }
)

Options:

OptionUse
returnDocument: "after"Return updated doc
upsert: trueCreate if missing
projectionLimit returned fields

Related: findOneAndReplace, findOneAndDelete.

Update vs SQL

SQLMongoDB
UPDATE posts SET views = views + 1 WHERE slug = 'x'updateOne({ slug }, { $inc: { views: 1 } })
INSERT ... ON DUPLICATE KEY UPDATEupdateOne(..., { upsert: true })

Transactions for multi-doc updates — chapter 14.

Common Mistakes

MistakeResultFix
Missing $setDocument corruptionOperator form
updateMany without filterAll docs changedAlways narrow filter in prod
$push unbounded16 MB risk$slice, separate collection
Race on read-then-writeLost updatesfindOneAndUpdate or transaction

Post-Chapter Checklist

  • $set, $inc, $unset on posts
  • $push / $pull on array fields
  • upsert: true creates missing document
  • findOneAndUpdate returns updated document

FAQ

modifiedCount 0 but matched?

Document already had target values—no change written.

Update _id?

Generally forbidden. Insert new doc and delete old if needed.

Array filters?

arrayFilters option for positional updates on matched array elements—advanced.

Bulk updates?

bulkWrite in drivers — PyMongo.

Soft delete?

$set: { deletedAt: new Date() } and filter { deletedAt: { $exists: false } } in queries.