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
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('...') } }insertOnetakes one document;insertManytakes an array of documents.- The result reports
acknowledged: truewhen the server confirmed the write, plus the new_idvalues. - 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
_idcan be any unique value:{ _id: 'SKU-1042', name: 'Lamp' }. Use one when it's naturally unique and never changes, such as an ISBN. _idcan't be changed after insertion, so don't use values that might change, such as an email address._idis always indexed, so finding a document by_idis 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 --jsonArrayMongoDB 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.
Inserting one and many documents
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()switched to db shop
{ acknowledged: true, insertedId: 1 }
{ acknowledged: true, insertedIds: { '0': 2, '1': 3, '2': 4 } }
4Line-by-line explanation
- Line 2insertOne reports the _id of the document it added.
- Lines 3 to 7insertMany takes an array and reports each new _id by its position.
- Line 6Documents can contain different fields, like size here.
- Line 8All four documents are now in the collection.
Duplicate keys and ordered inserts
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(' '){ acknowledged: true, insertedIds: { '0': 'A', '1': 'B' } }
Ordered: 11000 after inserting 1
Unordered: 11000 after inserting 2
A B C E FLine-by-line explanation
- Line 4A is already used, so this insert fails with error code 11000.
- Line 6Ordered inserts stop at the error: C was saved, but D was never tried.
- Line 10ordered: false keeps going after the failure on B, so E and F are saved.
- Line 15D is missing because the ordered insert stopped before reaching it.
Dates, ObjectIds and nested data
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())2 Ada 2026
objectLine-by-line explanation
- Line 1The result of insertOne holds the generated ObjectId.
- Lines 2 to 6A whole order, including its items, is stored as one document.
- Line 8ISODate stores a real date, which sorts and compares correctly.
- Line 10findOne by _id fetches the document straight back.
- Line 12getTimestamp returns the Date when the ObjectId was created.
Common MongoDB CRUD Mistakes
Passing several documents to insertOne
db.products.insertOne({ name: 'A' }, { name: 'B' }) // only A is inserted; the second object is treated as optionsdb.products.insertMany([{ name: 'A' }, { name: 'B' }])Using a changeable value as _id
db.users.insertOne({ _id: 'ada@example.com', name: 'Ada' }) // emails change, but _id can'tdb.users.insertOne({ email: 'ada@example.com', name: 'Ada' })
db.users.createIndex({ email: 1 }, { unique: true })Dates stored as strings
db.events.insertOne({ title: 'Launch', date: '03/01/2026' }) // March 1 or 3 January? Sorts as textdb.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.
Complete the command that adds several documents at once.
db.tags.([{ name: 'new' }, { name: 'sale' }])
What does insertOne return when it succeeds?
What error does inserting a duplicate _id cause?
How many documents are saved by this ordered insert if B already exists?
db.c.insertMany([{ _id: 'A' }, { _id: 'B' }, { _id: 'C' }])
What does { ordered: false } change in insertMany?
MongoDB CRUD Quiz
5 questions to check what you learned.
Is a collection created automatically when you first insert into it?
- No
- Yes
- Only in Atlas
- Only with insertMany
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
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
Can _id be changed after a document is inserted?
- No, it's immutable
- Yes, with updateOne
- Only for ObjectIds
- Only by an admin
Which tool imports a JSON file into a collection from the command line?
- mongodump
- mongosh --load
- mongorestore only
- mongoimport