Filter concepts by levelShowing all levels.

MongoDB · CRUD Operations

CRUD Operations

The nine methods, upserts, update operators, and shaping the write and the read

  • "One" stops at the first matchnot "the only match" — updateMany/deleteMany affect every match
  • upsert: trueupdate on a match, insert otherwise — one atomic call
  • $inc is atomicsafe under concurrent writes, unlike read-then-$set
  • skip() cost growsdeep pagination gets slower — cursor pagination does not

1.The CRUD method surface

Nine methods cover CRUD in practice: insertOne/Many create, find/findOne read, updateOne/Many change fields, replaceOne swaps a whole document, deleteOne/Many remove. Each has a "One" and, where it makes sense, a plural form.

Key features

  • insertOne/insertMany create; find/findOne read; updateOne/updateMany change fields
  • replaceOne swaps a whole document, keeping only _id; there is no replaceMany
  • deleteOne/deleteMany remove documents matching a filter
  • find() returns a cursor; findOne() returns one document (or null) directly
  • Every method except insert takes a filter as its first argument

The nine CRUD methods

The nine CRUD methods
MethodVerbMatchesReturns
insertOne(doc)createn/athe inserted _id
insertMany(docs)createn/ainserted _ids
find(filter)readall matchesa cursor
findOne(filter)readfirst matcha document or null
updateOne(filter, update)change fieldsfirst matcha result summary
updateMany(filter, update)change fieldsall matchesa result summary
replaceOne(filter, doc)swap whole docfirst matcha result summary
deleteOne(filter)removefirst matcha result summary
deleteMany(filter)removeall matchesa result summary
One method per verb, "One" vs. plural

Create

insertOne

one document

insertMany

many documents

Read / Update / Delete

find / findOne

all / first match

updateOne / updateMany

first / all matches

deleteOne / deleteMany

first / all matches

  • Create
    • insertOne — one document
    • insertMany — many documents
  • Read / Update / Delete
    • find / findOne — all / first match
    • updateOne / updateMany — first / all matches
    • deleteOne / deleteMany — first / all matches

Command

text
db.<collection>.<method>(<filter>, <update or doc>, <options>)

insertOne/Many, find/findOne, updateOne/Many, replaceOne, deleteOne/Many. "One" stops at the first match — it does not mean "the only match."

2.Upserts

An upsert — updateOne/updateMany with { upsert: true } — updates a matching document if one exists, or inserts a new one built from the filter and update if none does. It replaces a separate "check, then insert or update" round trip.

Key features

  • upsert: true on updateOne/updateMany triggers an insert when nothing matches
  • The inserted document combines the filter's equality conditions with the update
  • $setOnInsert sets fields only on the insert branch, never on a normal update
  • An upsert is one atomic operation — no separate exists-check-then-write race
  • Wrong equality filters in an upsert can insert unexpected duplicate-looking documents

What an upsert does in each case

What an upsert does in each case
Filter matches?Result
Yes, one documentthat document is updated, same as a normal update
Yes, several documents (updateMany)all of them are updated
No documentsa new document is inserted, from filter + update + $setOnInsert
What upsert: true decides
yesno

Filter runs

Match found?

Update it

Insert new

  • Filter runs
    • leads to Match found?
  • Match found?
    • leads to Update it (yes)
    • leads to Insert new (no)
  • Update it
  • Insert new

Command

text
db.<collection>.updateOne(filter, update, { upsert: true })

upsert: true updates on a match, inserts otherwise. $setOnInsert runs only on the insert branch — use it for create-once fields.

3.Field update operators

Update operators change specific fields without reading the document first: $set assigns, $unset removes, $inc/$mul do arithmetic in place, $min/$max apply conditionally, $rename renames a field, $currentDate stamps now.

Key features

  • $set assigns a field a new value; $unset removes a field entirely
  • $inc/$mul add to or multiply a numeric field in place, atomically
  • $min/$max only apply if the new value is smaller/larger than the current one
  • $rename changes a field's name, keeping its value
  • $currentDate sets a field to the current date/time server-side

Field update operators

Field update operators
OperatorEffect
$setassigns a field the given value
$unsetremoves the field entirely
$incadds the given amount to a numeric field (can be negative)
$mulmultiplies a numeric field by the given amount
$minsets the field only if the given value is smaller than the current one
$maxsets the field only if the given value is larger than the current one
$renamerenames a field, keeping its value
$currentDatesets a field to the current date, evaluated server-side
An update operator edits in place, no read-modify-write

document

as stored

$inc: { n: 1 }

applied atomically

document

n is one higher

  1. document — as stored
  2. $inc: { n: 1 } — applied atomically
  3. document — n is one higher

Command

text
{ $set: {...}, $unset: {...}, $inc: {...}, $mul: {...}, $min: {...}, $max: {...}, $rename: {...}, $currentDate: {...} }

$set/$unset assign/remove; $inc/$mul do atomic arithmetic; $min/$max apply conditionally; $rename renames; $currentDate stamps now, server-side.

4.Array update operators

$push appends (allows duplicates); $addToSet appends only if new; $pop removes from an end; $pull/$pullAll remove matching values. $each/$slice/$sort are modifiers inside $push to add several values, cap length, and keep order.

Key features

  • $push appends a value; $addToSet appends only if the value is not already present
  • $pop removes the first (-1) or last (1) array element
  • $pull removes every element matching a condition; $pullAll removes exact given values
  • $each inside $push adds multiple values in one call
  • $slice (with $each) caps array length; $sort (with $each) keeps it ordered

Array update operators

Array update operators
OperatorEffect
$pushappends one value (or, with $each, several)
$addToSetappends a value only if not already present
$popremoves the first (-1) or last (1) element
$pullremoves every element matching a condition
$pullAllremoves every occurrence of the given exact values
$eachmodifier: add several values in one $push
$slicemodifier: cap the array to N elements after the update
$sortmodifier: sort the array after $each adds to it

Command

text
{ $push: { field: { $each: [...], $slice: N, $sort: {...} } } }

$push/$addToSet add (with/without duplicates); $pop/$pull/$pullAll remove; $each/$slice/$sort are modifiers inside $push.

5.Positional update patterns

The $ positional operator updates the array element that matched the query filter, without knowing its index. $[] updates every element; $[<id>] (filtered positional) updates only elements matching a separate arrayFilters condition.

Key features

  • $ updates the array element that matched the query filter's condition
  • $[] updates every element in the array, unconditionally
  • $[<identifier>] updates only elements matching an arrayFilters condition
  • The query filter must actually reference the array field for $ to have a match to use
  • arrayFilters lets the matched condition differ from the top-level query filter

The three positional forms

The three positional forms
OperatorUpdatesRequires
$the first array element the query filter matchedthe query filter to reference the array
$[]every element in the arraynothing extra
$[<id>]elements matching an arrayFilters conditionan arrayFilters option

Command

text
{ $set: { "field.$.nested": value } }                          // $
{ $set: { "field.$[].nested": value } }                         // $[]
{ $set: { "field.$[id].nested": value } }, { arrayFilters: [...] } // $[<id>]

$ updates the query-matched array element; $[] updates all elements; $[<id>] updates elements matching a separate arrayFilters condition.

6.Projection and field selection

A projection, find()'s second argument, chooses which fields come back: { field: 1 } includes only named fields (plus _id by default), { field: 0 } excludes named fields and returns everything else. The two forms cannot normally be mixed.

Key features

  • { field: 1 } includes only that field (and _id, unless excluded explicitly)
  • { field: 0 } excludes that field, returning everything else
  • Inclusion and exclusion cannot normally be mixed in one projection
  • { _id: 0 } is the one exception — allowed alongside an inclusion projection
  • A smaller projection reduces network transfer, not query-planning cost by itself

Projection forms

Projection forms
ProjectionReturns
{}every field (the default)
{ title: 1 }only _id and title
{ title: 1, _id: 0 }only title (the one allowed inclusion/exclusion mix)
{ internalNotes: 0 }everything except internalNotes

Command

text
db.<collection>.find(filter, { field1: 1, field2: 1 })   // or { field: 0, ... }

find()'s second argument is a projection: { field: 1 } includes, { field: 0 } excludes. The two forms cannot mix, except { _id: 0 }.

7.sort, skip, limit — and why skip gets expensive

sort() orders results, limit() caps how many come back, and skip() discards the first N — but skip still walks past those N documents internally, so a deep skip (page 10,000) gets slower as N grows, even at the same page size.

Key features

  • sort(), skip() and limit() chain onto a find() cursor
  • skip(N) discards the first N matched documents before returning results
  • skip's cost scales with N — it does not jump directly to document N+1
  • A page-number-based UI (skip = page × pageSize) gets slower deeper into the result set
  • Cursor/range pagination (indexed field past the last seen value) avoids this cost

Pagination cost comparison

Pagination cost comparison
ApproachCost at page 2Cost at page 10,000
skip/limitcheapexpensive — must walk past all prior matches
Cursor (range) paginationcheapcheap — jumps straight to the bookmark via an index

Command

text
db.<collection>.find(filter).sort({ field: 1 }).skip(N).limit(M)

skip(N) still walks past N documents internally — deep pagination gets slower. Cursor/range pagination (later, section 37) avoids that cost.

8.bulkWrite() — ordered vs. unordered

bulkWrite() sends a mixed batch of insert/update/delete operations in one call. Ordered (the default) stops at the first failure, leaving later operations unrun; unordered keeps going, running every operation regardless of earlier failures.

Key features

  • bulkWrite() takes an array of insert/update/replace/delete operations
  • Ordered (default): operations run in order, stopping at the first failure
  • Unordered: every operation is attempted, regardless of earlier failures
  • Unordered can be faster since operations may be parallelized server-side
  • The result reports which operations succeeded and which failed, either way

Ordered vs. unordered bulkWrite

Ordered vs. unordered bulkWrite
ModeOn a failureOrder guaranteed?
ordered: true (default)stops — later operations do not runyes
ordered: falsecontinues — every operation is attemptedno

Command

text
db.<collection>.bulkWrite([{ insertOne: {...} }, { updateOne: {...} }, ...], { ordered: true|false })

bulkWrite() batches mixed operations. Ordered (default) stops at the first failure; unordered keeps going and may run out of order.

Remember

  • insertOne/Many, find/findOne, updateOne/Many, replaceOne, deleteOne/Many — "One" stops at the first match.
  • upsert: true updates on a match, inserts otherwise. $setOnInsert runs only on the insert branch.
  • $set/$unset assign/remove; $inc/$mul are atomic arithmetic — safer than read-then-write under concurrency.
  • skip(N) still walks past N documents internally — deep pagination gets slower as N grows.

Pro tip

  • $ / $[] / $[<id>] update an array element without knowing its index — $ uses the query match, $[<id>] uses arrayFilters.
  • bulkWrite({ ordered: false }) keeps running after a failure and may be faster; ordered (default) stops at the first one.

Next up

  • Query Language
  • Data Modeling
  • Indexing Fundamentals

Sources

  • CRUD — mongodb.com/docs/manual/crud/
  • Update operators — mongodb.com/docs/manual/reference/operator/update-field/
  • Checked 2026-08-20

Spotted a mistake on this page? Tell us.