MongoDB Insert Documents

Add data to MongoDB with insertOne and insertMany, choose or generate _id values, handle duplicate key errors, understand ordered and unordered bulk inserts, and read the result each insert returns.

Lesson 2 of 43Beginner17 min read

Every database starts with putting data in. In MongoDB, you add documents to a collection with insertOne, for a single document, or insertMany, for several at once. If the collection doesn't exist yet, MongoDB creates it on the first insert, so you can start storing data immediately.

Each document needs a unique _id. You can let MongoDB generate one, an ObjectId, which is unique across servers and even records when it was created. Or you can supply your own, such as a product code or an order number, when you already have a natural unique identifier. Trying to insert a second document with an existing _id fails with a duplicate key error, which is MongoDB protecting you from accidental overwrites.

Inserting many documents raises a practical question: what happens if one of them fails? With ordered inserts, the default, MongoDB stops at the first error. With unordered inserts, it continues with the rest. In this lesson you'll insert single and multiple documents, work with nested data, arrays and dates, read the acknowledgement MongoDB returns, and handle failures sensibly.

insertOne and insertMany

MongoDB Shell
db.products.insertOne({ name: 'Mug', price: 8.5 })
// { acknowledged: true, insertedId: ObjectId('...') }

db.products.insertMany([
  { name: 'Lamp', price: 24 },
  { name: 'Pen', price: 1.2 }
])
// { acknowledged: true, insertedIds: { '0': ObjectId('...'), '1': ObjectId('...') } }
  • insertOne takes one document; insertMany takes an array of documents.
  • The result reports acknowledged: true when the server confirmed the write, plus the new _id values.
  • Documents can contain nested documents, arrays, dates and any other BSON type.
  • Field names are case-sensitive and shouldn't start with $ or contain ., which have special meaning in queries.

Choosing _id values

  • ObjectId (the default) is a 12-byte value that includes a timestamp, so ObjectId('...').getTimestamp() tells you when the document was created, and ids sort roughly by creation time.
  • A custom _id can be any unique value: { _id: 'SKU-1042', name: 'Lamp' }. Use one when it's naturally unique and never changes, such as an ISBN.
  • _id can't be changed after insertion, so don't use values that might change, such as an email address.
  • _id is always indexed, so finding a document by _id is fast.

Errors, ordered inserts and write concern

Inserting a duplicate _id (or a value that breaks any unique index) raises error E11000 duplicate key error.

With insertMany:

  • Ordered (default): documents are inserted in order and the operation stops at the first error. Documents before it are kept.
  • Unordered, { ordered: false }: MongoDB tries every document, reports all the failures at the end, and can be faster.

A write concern controls how much confirmation you wait for. The default, { w: 'majority' } on replica sets, waits until most servers have the data, which protects it from being lost if one server fails.

MongoDB CRUD Syntax

Insert syntax

db.c.insertOne({ field: 'value' })
db.c.insertOne({ _id: 'A1', name: 'Custom id' })
db.c.insertMany([{ a: 1 }, { a: 2 }])
db.c.insertMany(docs, { ordered: false })
db.c.insertOne({ createdAt: new Date(), tags: ['x', 'y'], meta: { v: 1 } })
ObjectId().getTimestamp()
// mongoimport --db shop --collection products --file products.json --jsonArray

MongoDB CRUD Summary

  • insertOne adds one document; insertMany adds an array of documents.
  • Collections are created automatically on the first insert.
  • MongoDB generates an ObjectId _id unless you supply a unique value yourself.
  • A repeated _id causes an E11000 duplicate key error.
  • insertMany stops at the first error by default; ordered: false tries every document.

MongoDB CRUD Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Inserting one and many documents

MongoDB Shell
use shop
db.products.insertOne({ _id: 1, name: 'Mug', price: 8.5, tags: ['kitchen'] })
db.products.insertMany([
  { _id: 2, name: 'Lamp', price: 24, tags: ['home', 'lighting'] },
  { _id: 3, name: 'Pen', price: 1.2, tags: [] },
  { _id: 4, name: 'Rug', price: 79, size: { w: 120, h: 180 } }
])
db.products.countDocuments()
Output
switched to db shop
{ acknowledged: true, insertedId: 1 }
{ acknowledged: true, insertedIds: { '0': 2, '1': 3, '2': 4 } }
4
Line-by-line explanation
  1. Line 2insertOne reports the _id of the document it added.
  2. Lines 3 to 7insertMany takes an array and reports each new _id by its position.
  3. Line 6Documents can contain different fields, like size here.
  4. Line 8All four documents are now in the collection.
Example 2

Duplicate keys and ordered inserts

MongoDB Shell
db.codes.insertMany([{ _id: 'A' }, { _id: 'B' }])

try {
  db.codes.insertMany([{ _id: 'C' }, { _id: 'A' }, { _id: 'D' }])
} catch (e) {
  print(`Ordered: ${e.code} after inserting ${e.result.insertedCount}`)
}

try {
  db.codes.insertMany([{ _id: 'E' }, { _id: 'B' }, { _id: 'F' }], { ordered: false })
} catch (e) {
  print(`Unordered: ${e.code} after inserting ${e.result.insertedCount}`)
}

db.codes.find().toArray().map(d => d._id).join(' ')
Output
{ acknowledged: true, insertedIds: { '0': 'A', '1': 'B' } }
Ordered: 11000 after inserting 1
Unordered: 11000 after inserting 2
A B C E F
Line-by-line explanation
  1. Line 4A is already used, so this insert fails with error code 11000.
  2. Line 6Ordered inserts stop at the error: C was saved, but D was never tried.
  3. Line 10ordered: false keeps going after the failure on B, so E and F are saved.
  4. Line 15D is missing because the ordered insert stopped before reaching it.
Example 3

Dates, ObjectIds and nested data

MongoDB Shell
const result = db.orders.insertOne({
  customer: { name: 'Ada', email: 'ada@example.com' },
  items: [
    { sku: 'MUG-1', qty: 2, price: 8.5 },
    { sku: 'LAMP-3', qty: 1, price: 24 }
  ],
  status: 'paid',
  createdAt: ISODate('2026-03-01T09:30:00Z')
})
const order = db.orders.findOne({ _id: result.insertedId })
print(order.items.length, order.customer.name, order.createdAt.getUTCFullYear())
print(typeof result.insertedId.getTimestamp())
Output
2 Ada 2026
object
Line-by-line explanation
  1. Line 1The result of insertOne holds the generated ObjectId.
  2. Lines 2 to 6A whole order, including its items, is stored as one document.
  3. Line 8ISODate stores a real date, which sorts and compares correctly.
  4. Line 10findOne by _id fetches the document straight back.
  5. Line 12getTimestamp returns the Date when the ObjectId was created.

Common MongoDB CRUD Mistakes

Passing several documents to insertOne

Don't
db.products.insertOne({ name: 'A' }, { name: 'B' })   // only A is inserted; the second object is treated as options
Do
db.products.insertMany([{ name: 'A' }, { name: 'B' }])

Using a changeable value as _id

Don't
db.users.insertOne({ _id: 'ada@example.com', name: 'Ada' })   // emails change, but _id can't
Do
db.users.insertOne({ email: 'ada@example.com', name: 'Ada' })
db.users.createIndex({ email: 1 }, { unique: true })

Dates stored as strings

Don't
db.events.insertOne({ title: 'Launch', date: '03/01/2026' })   // March 1 or 3 January? Sorts as text
Do
db.events.insertOne({ title: 'Launch', date: ISODate('2026-03-01T10:00:00Z') })

MongoDB CRUD in Real Projects

Inserting data in applications

Applications insert documents through a driver, such as await db.collection('orders').insertOne(order) in Node.js, and use the returned insertedId to redirect to the new item. Import jobs load thousands of records with insertMany({ ordered: false }) so a few bad rows don't stop the rest, and mongoimport loads JSON or CSV files from the command line. Unique indexes stop duplicate accounts and order numbers at the database level.

MongoDB CRUD FAQ

How do I insert a document only if it doesn't already exist?

Use updateOne with upsert: true and put the new fields in $setOnInsert: db.users.updateOne({ email: 'ada@example.com' }, { $setOnInsert: { name: 'Ada' } }, { upsert: true }). If a matching document exists, nothing changes; otherwise one is inserted. Back it with a unique index on email so two simultaneous requests can't both create a document.

How do I get the _id of a document I just inserted?

Read it from the result: insertOne returns { acknowledged: true, insertedId: ... }, and insertMany returns insertedIds, an object keyed by each document's position in the array. In Node.js that's const { insertedId } = await users.insertOne(doc). The driver also adds the generated _id to the object you passed in.

How many documents can insertMany insert at once?

There's no small fixed limit you need to manage yourself. The server accepts up to 100,000 writes per batch, and drivers and mongosh split a larger array into several batches automatically. Each individual document must still be under the 16 MB document limit.

How do I find out which documents failed in an unordered insertMany?

The error thrown is a bulk write error whose writeErrors array lists each failure, with its index in your input array, an error code such as 11000 and a message. Every document that didn't fail is still inserted, and the error's result shows how many succeeded. Log the failing indexes so you can fix and retry just those records.

Should I use insert(), save() or insertOne() in mongosh?

Use insertOne and insertMany. The old insert() method still works in mongosh but prints a deprecation warning, and save() is a legacy helper you shouldn't rely on. The newer methods return clear results with insertedId or insertedIds, and they match the method names in every official driver.

MongoDB CRUD Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the command that adds several documents at once.

db.tags.([{ name: 'new' }, { name: 'sale' }])
Multiple choiceeasy

What does insertOne return when it succeeds?

Multiple choicemedium

What error does inserting a duplicate _id cause?

Predict the outputmedium

How many documents are saved by this ordered insert if B already exists?

db.c.insertMany([{ _id: 'A' }, { _id: 'B' }, { _id: 'C' }])
Multiple choicehard

What does { ordered: false } change in insertMany?

MongoDB CRUD Quiz

5 questions to check what you learned.

  1. Is a collection created automatically when you first insert into it?

    • No
    • Yes
    • Only in Atlas
    • Only with insertMany
  2. What extra information does an ObjectId contain?

    • A timestamp of when it was created
    • The user who created it
    • The collection name
    • The document size
  3. How should dates be stored?

    • As strings like "01/03/2026"
    • As numbers of days
    • As Date values, using new Date() or ISODate()
    • As separate day, month and year fields
  4. Can _id be changed after a document is inserted?

    • No, it's immutable
    • Yes, with updateOne
    • Only for ObjectIds
    • Only by an admin
  5. Which tool imports a JSON file into a collection from the command line?

    • mongodump
    • mongosh --load
    • mongorestore only
    • mongoimport