← Back to Index

CRUD
Insert

FILE 04_crud_insert
TOPIC insertOne · insertMany · Bulk · bulkWrite
LEVEL Foundation
01
Method Overview
Insert methods comparison
Overview
MethodInsertsReturnsStatus
insert()One or manyWriteResultDEPRECATED
insertOne()Single document{ acknowledged, insertedId }CURRENT
insertMany()Array of documents{ acknowledged, insertedIds }CURRENT
Bulk.insert()Many (low-level)BulkWriteResult on execute()LEGACY
bulkWrite()Mixed ops batchBulkWriteResultCURRENT
NOTEAll insert methods auto-generate an ObjectId for _id if not provided. If you provide a _id, it must be unique in the collection or you get E11000 duplicate key error.
02
insertOne()
Single document insertion
Single
// Signature
db.collection.insertOne(document, options)

// Auto-generated _id (ObjectId)
db.cars.insertOne({ model: "Tata", color: "blue" })
// → { acknowledged: true, insertedId: ObjectId("69a5...") }

// User-defined _id (any unique BSON value)
db.cars.insertOne({ _id: 1001, model: "Hero", color: "red" })
// → { acknowledged: true, insertedId: 1001 }

// Duplicate _id → throws immediately
db.cars.insertOne({ _id: 1001, model: "Other" })
// MongoServerError: E11000 duplicate key error collection: test.cars index: _id_

Return Object Fields

FieldTypeMeaning
acknowledgedBooleantrue if write concern was satisfied
insertedIdAnyThe _id of the newly inserted document
TIPUse insertOne() over deprecated insert(). It enforces single-document intent and throws on accidental array input.
03
insertMany()
Ordered vs unordered batch insert
Batch
// Signature
db.collection.insertMany([ doc1, doc2, ... ], { ordered: true|false })

// Basic usage — ordered: true is the DEFAULT
db.cars.insertMany([
  { model: "Hyundai", color: "purple" },
  { model: "Honda",   color: "red"    }
])
// → { acknowledged: true, insertedIds: { '0': ObjectId(...), '1': ObjectId(...) } }

Ordered vs Unordered

SettingOn ErrorUse When
ordered: true (default)Stops at first failure — previous docs are committed, remaining are skippedOrder matters; you want to fail fast
ordered: falseContinues processing all documents; reports all errors at end in BulkWriteErrorMaximum throughput; errors are non-critical
// Unordered — skips errors, inserts what it can
db.cars.insertMany([
  { _id: 1, model: "Ferrari" },
  { _id: 1, model: "Duplicate" },  // Dup key — skipped, not stopped
  { _id: 2, model: "BMW" }
], { ordered: false })
// Inserts _id:1 and _id:2; throws BulkWriteError with writeErrors array
// BulkWriteError: { writeErrors: [{ index: 1, code: 11000, ... }] }

// Ordered — stops at duplicate, BMW never inserted
db.cars.insertMany([
  { _id: 1, model: "Ferrari" },
  { _id: 1, model: "Duplicate" },  // Stops here
  { _id: 2, model: "BMW" }         // Never reached
])
// Only Ferrari is inserted
WARNWith ordered: true, documents before the failing one are already committed and not rolled back. insertMany() is not atomic across the full array.
04
Bulk Operations
Bulk.insert() · ordered · unordered · stateful gotcha
Bulk API

The Bulk API (legacy) builds up a batch of operations and sends them all at once with .execute(). The collection must already exist before using it.

Unordered Bulk (initializeUnorderedBulkOp)

var bulk = db.cars.initializeUnorderedBulkOp()
bulk.insert({ model: "Audi", color: "purple" })
bulk.find({ model: "BMW" }).remove()
bulk.execute()
// MongoDB may reorder ops by type (all inserts together, all removes together)
// for better performance. Errors don't stop remaining operations.

Ordered Bulk (initializeOrderedBulkOp)

var bulk = db.cars.initializeOrderedBulkOp()
bulk.insert({ model: "Audi", color: "purple" })
bulk.find({ model: "BMW" }).remove()
bulk.execute()
// Operations run in exact order. First error stops all remaining operations.

The Stateful Bulk Object Gotcha

DANGERThe bulk variable accumulates all staged operations — even across failed/crashed attempts in the same shell session. If you crash midway, the next bulk.insert() adds to the existing queue.
// Attempt 1: crashes on bulk.delete (wrong method name)
var bulk = db.cars.initializeUnorderedBulkOp()
bulk.insert({ model: "Audi" })
bulk.delete({ model: "BMW" })  // TypeError: bulk.delete is not a function
// Queue now has: [insert Audi]

// Attempt 2: crashes again on same wrong method
bulk.insert({ model: "Audi" })  // Queue: [insert, insert] — two Audis!
bulk.delete({ model: "BMW" })   // TypeError again

// Attempt 3: finally fixed — but 3 Audis get inserted
bulk.insert({ model: "Audi" })             // Queue: [insert×3, remove]
bulk.find({ model: "BMW" }).remove()       // correct syntax
bulk.execute()
// → insertedCount: 3 (not 1!) because of accumulated queue

// FIX: Re-initialize after any failure
var bulk = db.cars.initializeUnorderedBulkOp()  // Reset — clears queue
TIPType bulk (without calling any method) in the shell to inspect how many pending operations are queued before running execute().
05
bulkWrite()
Mixed operations in one command
Modern

bulkWrite() executes multiple different write operations (insert, update, delete) in a single round-trip to the server.

// Mixed operations example
db.cars.bulkWrite([
  { insertOne: { document: { model: "GT", color: "black" } } },
  { insertOne: { document: { model: "BT", color: "red"   } } },
  { updateOne: {
      filter: { model: "Audi" },
      update: { $set: { color: "silver" } }
  }},
  { deleteOne: { filter: { model: "BMW" } } }
])
// → {
//   acknowledged: true,
//   insertedCount: 2, insertedIds: { '0': ObjectId(...), '1': ObjectId(...) },
//   matchedCount: 1,  modifiedCount: 1,
//   deletedCount: 1,  upsertedCount: 0, upsertedIds: {}
// }

Supported Operation Types

OperationSyntax Key
Insert one documentinsertOne: { document: {...} }
Update first matchingupdateOne: { filter, update, upsert? }
Update all matchingupdateMany: { filter, update }
Replace entire documentreplaceOne: { filter, replacement }
Delete first matchingdeleteOne: { filter }
Delete all matchingdeleteMany: { filter }
NOTELike insertMany(), bulkWrite() also accepts { ordered: false } as a second argument to continue past errors.
06
Edge Cases
_id rules · immutability · migration · type issues
Edge Cases

_id is Immutable — Cannot Update After Insert

// Attempting to change _id throws immediately
db.cars.updateOne({ model: "Hero" }, { $set: { _id: "new-id" } })
// MongoServerError: Performing an update on the path '_id' would modify
// the immutable field '_id'

Migrating User-Defined _id to Auto-Generated ObjectId

// Single document: delete + re-insert without _id
var doc = db.myCol.findOne({ _id: "user-defined-123" })
db.myCol.deleteOne({ _id: "user-defined-123" })
delete doc._id                    // remove old _id from JS object
db.myCol.insertOne(doc)           // MongoDB auto-assigns new ObjectId

// Entire collection: aggregate → tempCollection → rename
db.myCol.aggregate([
  { $project: { _id: 0 } },      // strip all _id fields
  { $out: "tempCol" }             // output with new ObjectIds
])
db.myCol.drop()
db.tempCol.renameCollection("myCol")

_id: null is Valid but Allows Only One

db.test.insertOne({ _id: null, x: 1 })  // succeeds
db.test.insertOne({ _id: null, x: 2 })  // E11000 duplicate key — null already used

insertOne() with an Array — Throws

// insertOne() rejects arrays — use insertMany() instead
db.cars.insertOne([{ model: "A" }, { model: "B" }])
// MongoServerError: document must be a plain object

BSON 16MB Document Size Limit

// Inserting a document that exceeds 16MB throws:
// BSONObj size: 16777217 is invalid. Limit: 16777216 bytes
// Use GridFS for large binary files (images, videos, PDFs)
WARNIf insertMany() partially fails midway (ordered or unordered), documents already inserted are NOT rolled back. For all-or-nothing behavior, use a multi-document transaction.