MongoDBDatabases

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.

TT
Sarah Mitchell
6 min read
MongoDB CRUD Operations: Insert, Find, Update, Delete

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

javascript
// 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

javascript
// 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-byte ObjectId for _id if you don't provide one. You can supply your own _id of any type — but it must be unique within the collection.


Read: Querying Documents

find and findOne

javascript
// 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

javascript
// 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

javascript
// 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

javascript
// 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

javascript
// 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

javascript
// 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

javascript
// 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

javascript
// $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

javascript
// 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

javascript
// 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

javascript
// 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

javascript
// 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({}) vs drop(): 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:

javascript
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 } } } }
])