MongoDB CRUD Operations: Insert, Find, Update, Delete
Master MongoDB CRUD operations: insertOne, insertMany, find with operators, updateOne, updateMany, replaceOne, deleteOne, and deleteMany with real examples. Lesson 3 of MongoDB & NoSQL Mastery.

CRUD — Create, Read, Update, Delete — is the foundation of every database interaction. MongoDB's CRUD API is document-oriented: you work with JSON-like objects rather than rows and columns, and every operation has a rich set of options for atomic updates, partial field replacement, and bulk processing.
Previous: Lesson 2 — Installing MongoDB & Using mongosh
Create: Inserting Documents
insertOne
// Insert a single document — MongoDB adds _id automatically
db.products.insertOne({
name: "Wireless Keyboard",
brand: "Logitech",
price: 79.99,
stock: 142,
tags: ["electronics", "peripherals", "wireless"],
specs: {
connectivity: "Bluetooth",
batteryLife: "24 months",
layout: "US"
},
createdAt: new Date()
})
// Result contains the generated _id
// { acknowledged: true, insertedId: ObjectId('...') }insertMany
// Insert multiple documents in a single operation
db.products.insertMany([
{ name: "USB-C Hub", brand: "Anker", price: 49.99, stock: 87, tags: ["electronics", "accessories"] },
{ name: "Mechanical Keyboard", brand: "Keychron", price: 129.99, stock: 34, tags: ["electronics", "peripherals"] },
{ name: "Monitor Stand", brand: "Ergotron", price: 39.99, stock: 210, tags: ["accessories", "ergonomics"] }
])
// By default, ordered: true — stops on first error
// ordered: false continues inserting remaining documents even if one fails
db.products.insertMany(docs, { ordered: false })Note on
_id: MongoDB automatically generates a 12-byteObjectIdfor_idif you don't provide one. You can supply your own_idof any type — but it must be unique within the collection.
Read: Querying Documents
find and findOne
// Return all documents (use sparingly on large collections)
db.products.find()
// Return the first matching document
db.products.findOne({ brand: "Logitech" })
// Find with a simple equality filter
db.products.find({ brand: "Anker" })
// Find returns a cursor — iterate explicitly in scripts
const cursor = db.products.find({ tags: "electronics" })
cursor.forEach(doc => print(doc.name))Comparison Operators
// Price greater than 50
db.products.find({ price: { $gt: 50 } })
// Price between 30 and 100 (inclusive)
db.products.find({ price: { $gte: 30, $lte: 100 } })
// Stock not equal to 0
db.products.find({ stock: { $ne: 0 } })
// Price in a specific set
db.products.find({ price: { $in: [39.99, 49.99, 79.99] } })
// Brand not in a set
db.products.find({ brand: { $nin: ["Logitech", "Anker"] } })Logical Operators
// AND: all conditions must match (implicit in a filter object)
db.products.find({ brand: "Logitech", price: { $lt: 100 } })
// Explicit $and (needed when the same field appears twice)
db.products.find({ $and: [
{ price: { $gte: 40 } },
{ price: { $lte: 100 } }
]})
// OR: at least one condition must match
db.products.find({ $or: [
{ brand: "Logitech" },
{ brand: "Keychron" }
]})
// NOT
db.products.find({ price: { $not: { $gt: 100 } } })Array and Element Operators
// Documents where tags array contains "wireless"
db.products.find({ tags: "wireless" })
// Documents where tags contains ALL of the specified values
db.products.find({ tags: { $all: ["electronics", "peripherals"] } })
// Documents where tags array has exactly 2 elements
db.products.find({ tags: { $size: 2 } })
// Field exists and is not null
db.products.find({ specs: { $exists: true } })
// Field is of a specific BSON type
db.products.find({ price: { $type: "double" } })Projection: Selecting Fields
// Return only name and price (include _id by default)
db.products.find({}, { name: 1, price: 1 })
// Exclude _id
db.products.find({}, { name: 1, price: 1, _id: 0 })
// Exclude a specific field (all others returned)
db.products.find({}, { specs: 0 })
// Array slice — return only first 2 elements of tags
db.products.find({}, { name: 1, tags: { $slice: 2 } })Sorting, Limiting, and Skipping
// Sort by price ascending (1) or descending (-1)
db.products.find().sort({ price: 1 })
// Sort by brand ascending, then price descending
db.products.find().sort({ brand: 1, price: -1 })
// Limit results
db.products.find().sort({ price: -1 }).limit(5)
// Pagination: skip the first 10, return the next 10
db.products.find().sort({ _id: 1 }).skip(10).limit(10)Avoid
skip()for deep pagination on large collections — it scans and discards documents. Use range-based pagination (_id: { $gt: lastSeenId }) for efficient cursor-based pagination.
Update: Modifying Documents
updateOne and updateMany
// Update the first matching document
db.products.updateOne(
{ name: "Wireless Keyboard" }, // filter
{ $set: { price: 89.99, stock: 130 } } // update
)
// Update all matching documents
db.products.updateMany(
{ brand: "Logitech" },
{ $set: { brand: "Logitech MX" } }
)Update Operators
// $set — set field values
db.products.updateOne({ name: "USB-C Hub" }, {
$set: { "specs.ports": 7, updatedAt: new Date() }
})
// $unset — remove a field
db.products.updateOne({ name: "Monitor Stand" }, {
$unset: { tags: "" }
})
// $inc — increment or decrement a numeric field
db.products.updateOne({ name: "Wireless Keyboard" }, {
$inc: { stock: -1 } // decrement stock by 1 (simulate a sale)
})
// $push — append to an array
db.products.updateOne({ name: "USB-C Hub" }, {
$push: { tags: "usb-c" }
})
// $addToSet — append only if not already in the array
db.products.updateOne({ name: "USB-C Hub" }, {
$addToSet: { tags: "accessories" }
})
// $pull — remove a value from an array
db.products.updateOne({ name: "Mechanical Keyboard" }, {
$pull: { tags: "electronics" }
})
// $rename — rename a field
db.products.updateMany({}, {
$rename: { "brand": "manufacturer" }
})upsert — Insert if Not Found
// If a document matching the filter exists, update it.
// If not, insert a new document combining the filter and update.
db.products.updateOne(
{ sku: "KB-WIRELESS-001" },
{ $set: { name: "Wireless Keyboard Pro", price: 99.99, stock: 50 } },
{ upsert: true }
)replaceOne — Full Document Replacement
// Replace the entire document (except _id)
db.products.replaceOne(
{ name: "Monitor Stand" },
{
name: "Monitor Stand Pro",
brand: "Ergotron",
price: 59.99,
stock: 75,
createdAt: new Date()
}
)findOneAndUpdate — Atomic Read-Modify
// Return the document AFTER the update (default is before)
const updated = db.products.findOneAndUpdate(
{ name: "Wireless Keyboard" },
{ $inc: { stock: -1 } },
{ returnDocument: "after" }
)
print("New stock:", updated.stock)Delete: Removing Documents
// Delete the first matching document
db.products.deleteOne({ name: "Monitor Stand" })
// Delete all matching documents
db.products.deleteMany({ stock: 0 })
// Delete all documents in a collection (collection remains)
db.products.deleteMany({})
// Atomic find-and-delete (returns the deleted document)
const removed = db.products.findOneAndDelete({ name: "USB-C Hub" })
print("Removed:", removed.name)
deleteMany({})vsdrop():deleteMany({})removes all documents but keeps the collection, indexes, and metadata.db.collection.drop()removes everything including indexes — it is faster for clearing large collections.
Bulk Operations
For high-throughput writes, bulkWrite batches multiple operations into a single round trip:
db.products.bulkWrite([
{ insertOne: { document: { name: "Mouse Pad XL", price: 19.99, stock: 500 } } },
{ updateOne: {
filter: { name: "Wireless Keyboard" },
update: { $set: { price: 85.99 } }
}},
{ deleteOne: { filter: { stock: { $lt: 5 } } } }
])