2.1 Document Insertion Operations
Key Takeaways
- The 'insertOne()' method inserts a single document returning an 'insertedId', while 'insertMany()' inserts an array of documents returning an 'insertedIds' map.
- Bulk insertions execute as ordered writes ('ordered: true') by default, processing documents sequentially and halting immediately upon encountering the first error.
- Setting '{ ordered: false }' executes unordered bulk inserts, attempting insertion of all documents regardless of individual write errors and aggregating failures into a BulkWriteError.
- If a document is inserted without an '_id' field, MongoDB drivers automatically synthesize a unique 12-byte ObjectId before sending the payload over the wire.
- Duplicate primary keys trigger an E11000 duplicate key error, which does not roll back previously completed inserts unless executed inside a multi-document ACID transaction.
Document Insertion Operations
In MongoDB, creating new records is the foundation of the CRUD (Create, Read, Update, Delete) lifecycle. Unlike relational database management systems that require explicit table declarations (CREATE TABLE) and column-oriented INSERT INTO statements, MongoDB provides dynamic, document-oriented insertion methods that create databases and collections implicitly upon the first write.
Understanding how write operations behave—specifically regarding primary key generation, return payloads, bulk operation ordering, and error containment—is a core domain on the MongoDB Associate Developer certification exam.
Core Insertion Methods: insertOne() and insertMany()
Modern MongoDB drivers and the MongoDB Shell (mongosh) provide two primary methods for inserting documents: db.collection.insertOne() and db.collection.insertMany(). Legacy methods such as db.collection.insert() and db.collection.save() are deprecated and should not be used in modern application development.
+-------------------------------------------------------------------------+
| MongoDB Insertion Methods |
| |
| +----------------------------------+ +-----------------------------+ |
| | insertOne(doc, opts) | | insertMany([docs], opts) | |
| | | | | |
| | Inserts a single BSON document. | | Inserts an array of BSON | |
| | Returns: | | documents in batches. | |
| | - acknowledged: true/false | | Returns: | |
| | - insertedId: <_id value> | | - acknowledged: true/false | |
| | | | - insertedIds: { '0': ... } | |
| +----------------------------------+ +-----------------------------+ |
+-------------------------------------------------------------------------+
1. Single Document Insertion: insertOne()
The insertOne() method adds exactly one BSON document to the target collection. If the collection does not already exist, MongoDB creates it automatically.
Syntax
db.collection.insertOne(
<document>,
{
writeConcern: <document>
}
)
Example: Registering a Customer Account
// In mongosh:
const insertResult = db.customers.insertOne({
username: "jdoe_dev",
email: "jdoe@example.com",
tier: "Premium",
loyalty_points: NumberInt(450),
profile: {
first_name: "John",
last_name: "Doe",
country: "USA"
},
created_at: new Date()
});
console.log(insertResult);
Return Document Structure
When an insertOne() operation succeeds, MongoDB returns a document containing two fields:
{
"acknowledged": true,
"insertedId": ObjectId("66d57a10f1e8a93b4c5d6e01")
}
acknowledged: A boolean indicating whether the write was acknowledged by the server according to the specified write concern (e.g.,w: 1orw: "majority").insertedId: The value of the_idfield for the inserted document. If the document lacked an_id, this contains the newly generatedObjectId.
2. Batch Document Insertion: insertMany()
The insertMany() method inserts an array of documents into a collection in an efficient batch operation over the network.
Syntax
db.collection.insertMany(
[ <document 1>, <document 2>, ... ],
{
writeConcern: <document>,
ordered: <boolean>
}
)
Example: Batch Inserting Products
const batchResult = db.products.insertMany([
{
sku: "MUG-BLU-001",
title: "Ceramic Coffee Mug - Blue",
price: NumberDecimal("14.99"),
in_stock: true
},
{
sku: "MUG-RED-002",
title: "Ceramic Coffee Mug - Red",
price: NumberDecimal("14.99"),
in_stock: true
},
{
sku: "COASTER-SET-04",
title: "Cork Coaster 4-Pack",
price: NumberDecimal("9.50"),
in_stock: false
}
]);
console.log(batchResult);
Return Document Structure
{
"acknowledged": true,
"insertedIds": {
"0": ObjectId("66d57a20f1e8a93b4c5d6e02"),
"1": ObjectId("66d57a20f1e8a93b4c5d6e03"),
"2": ObjectId("66d57a20f1e8a93b4c5d6e04")
}
}
acknowledged: Confirms server acknowledgment.insertedIds: A key-value map where each key is the zero-based integer index of the document in the input array, and the value is the corresponding_idassigned to that document.
The _id Primary Key & Automatic Generation
Every MongoDB document stored in a collection must possess a unique, immutable primary key in the top-level _id field. The database engine automatically builds a unique index on _id when the collection is initialized.
Automatic Client-Side Synthesis
If an application submits a document that lacks an _id field, the official MongoDB driver (or mongod if bypassing standard drivers) automatically generates a 12-byte BSON ObjectId and injects it into the document before transmitting the write payload across the network.
Application Document: { name: "Alice", role: "Admin" }
|
v (Driver injects _id)
Wire Protocol Payload: { _id: ObjectId("66d5..."), name: "Alice", role: "Admin" }
Custom _id Types
While ObjectId is the default, MongoDB allows developers to supply custom values for _id. Any BSON data type can serve as an _id, provided it is not an array:
// Valid custom _id types:
db.users.insertOne({ _id: "user_alpha_99", email: "alpha@test.com" }); // String
db.counters.insertOne({ _id: NumberLong(100452), counter_name: "hits" }); // 64-bit Integer
db.sensor_data.insertOne({
_id: { device_id: "DEV-402", timestamp: ISODate("2026-09-02T10:00:00Z") }, // Embedded Subdocument
reading: 24.8
});
// INVALID _id type (Throws MongoServerError: _id cannot be an array):
// db.inventory.insertOne({ _id: [1, 2, 3], item: "Invalid" });
Exam Trap: An
_idfield can be a String, Int32, Int64, Decimal128, UUID/Binary, or even an embedded Subdocument (commonly used as a compound natural primary key). However, an_idfield cannot be an Array.
Immutability of _id
Once a document has been persisted to disk, its _id value is strictly immutable. If an application requires a document to have a different _id, the existing document must be deleted and re-inserted under the new identifier.
Ordered vs. Unordered Bulk Insertions
When executing insertMany(), developers can configure the execution strategy via the ordered boolean option. This setting fundamentally alters how MongoDB executes writes and handles runtime errors.
| Operational Aspect | Ordered Inserts (ordered: true) | Unordered Inserts (ordered: false) |
|---|---|---|
| Default Behavior | Yes (Default if omitted) | No (Must be explicitly specified) |
| Execution Order | Strictly serial (Document 0, then 1, then 2...) | Non-deterministic / Arbitrary (Parallelized across shards) |
| Behavior on Error | Halts immediately on the first failure | Continues processing all remaining documents |
| Subsequent Documents | Not processed; write operation aborts | All remaining valid documents are inserted |
| Previous Documents | Remain in the database (No rollback) | Remain in the database (No rollback) |
| Network & Sharding | Sequential batching to shard targets | High throughput; can be split and processed in parallel |
| Error Payload | Single error report with index of failure | BulkWriteError aggregating all write errors across array |
Ordered Execution Mechanics (ordered: true)
In an ordered insert, MongoDB guarantees that documents are inserted in the exact sequence they appear in the array. If an error occurs (such as a duplicate key collision on document index 2), the operation immediately aborts.
Input Array: [ Doc 0 (Valid), Doc 1 (Valid), Doc 2 (Duplicate), Doc 3 (Valid), Doc 4 (Valid) ]
|
v
Step 1: Insert Doc 0 ---> SUCCESS
Step 2: Insert Doc 1 ---> SUCCESS
Step 3: Insert Doc 2 ---> ERROR (E11000 Duplicate Key)
|
+---> EXECUTION HALTS IMMEDIATELY
Doc 3 and Doc 4 are NEVER processed!
// Executing an ordered insertMany:
try {
db.inventory.insertMany([
{ _id: 101, item: "Notebook" },
{ _id: 102, item: "Pen" },
{ _id: 102, item: "Marker" }, // Duplicate _id 102!
{ _id: 103, item: "Eraser" },
{ _id: 104, item: "Ruler" }
], { ordered: true });
} catch (e) {
console.error("Bulk write failed:", e.message);
}
// Result in database:
// Documents 101 and 102 (Notebook, Pen) ARE in the collection.
// Document 102 (Marker) failed.
// Documents 103 and 104 (Eraser, Ruler) WERE NEVER ATTEMPTED.
Unordered Execution Mechanics (ordered: false)
In an unordered insert, MongoDB makes no guarantees regarding insertion sequence. MongoDB optimizes throughput by reordering operations and distributing writes concurrently across shards or storage threads. If an error occurs on a specific document, MongoDB records the error and continues processing all remaining documents in the array.
Input Array: [ Doc 0 (Valid), Doc 1 (Valid), Doc 2 (Duplicate), Doc 3 (Valid), Doc 4 (Valid) ]
|
v (ordered: false)
Attempt Doc 0 ---> SUCCESS
Attempt Doc 1 ---> SUCCESS
Attempt Doc 2 ---> ERROR (E11000) [Recorded in BulkWriteError]
Attempt Doc 3 ---> SUCCESS
Attempt Doc 4 ---> SUCCESS
|
+---> ALL valid documents (0, 1, 3, 4) are persisted to disk!
// Executing an unordered insertMany:
try {
db.inventory.insertMany([
{ _id: 201, item: "Monitor" },
{ _id: 202, item: "Keyboard" },
{ _id: 202, item: "Mouse" }, // Duplicate _id 202!
{ _id: 203, item: "Webcam" },
{ _id: 204, item: "Headset" }
], { ordered: false });
} catch (e) {
console.log("Errors captured:", e.writeErrors.length);
console.log("First error index:", e.writeErrors[0].index);
}
// Result in database:
// Documents 201, 202 (Keyboard), 203, and 204 ALL exist in the collection!
// Only the duplicate document (Mouse at index 2) failed.
Critical Exam Concept: Neither ordered nor unordered
insertMany()performs a transactional rollback upon error. Documents successfully inserted prior to a failure (in ordered mode) or all valid documents across the batch (in unordered mode) remain permanently written in the collection unless executed inside an explicit multi-document ACID transaction (session.startTransaction()).
Duplicate Key Errors (E11000)
A Duplicate Key Error (Error Code 11000 / E11000) occurs whenever a write operation attempts to insert or update a document with a key value that already exists in an index marked with a unique constraint (including the default _id_ index).
Anatomy of an E11000 Error
MongoServerError: E11000 duplicate key error collection: store_db.inventory index: _id_ dup key: { _id: 102 }
When inspecting a BulkWriteError in application code:
try {
db.users.insertMany(userBatch, { ordered: false });
} catch (err) {
if (err.name === "BulkWriteError") {
console.log(`Inserted ${err.result.nInserted} documents.`);
err.writeErrors.forEach(we => {
if (we.code === 11000) {
console.error(`Duplicate key at array index ${we.index}: ${we.errmsg}`);
} else {
console.error(`Other error at array index ${we.index}: ${we.errmsg}`);
}
});
}
}
Insert Methods Comparison Summary
| Feature | insertOne() | insertMany() (Ordered) | insertMany() (Unordered) |
|---|---|---|---|
| Input Type | Single BSON object | Array of BSON objects | Array of BSON objects |
| Network Overhead | 1 round-trip per document | 1 batched round-trip | 1 batched round-trip |
| Throughput | Low (fine-grained) | High | Maximum (parallelized) |
| On Duplicate Error | Throws exception immediately | Halts at error index; aborts rest | Collects error; inserts remainder |
| Atomicity | Atomic at single-doc level | Not atomic as a whole batch | Not atomic as a whole batch |
| Primary Use Case | Real-time user interactions | Sequential workflows | Bulk ETL data pipelines |
An application executes db.collection.insertMany() with an array of five documents. Document index 2 contains a duplicate '_id' that causes an E11000 write error. If the operation is executed with '{ ordered: false }', which documents will exist in the collection after execution?
What is the structure of the return document when executing 'db.collection.insertMany()' successfully on a batch of three documents in the MongoDB Shell?
What happens when a developer calls 'db.collection.insertOne()' with a document that does not contain an '_id' field?
A developer executes 'db.orders.insertMany([docA, docB, docC, docD])' using default options. The collection already contains a document with the same '_id' as 'docC'. What is the resulting state of the database and execution flow?