MongoDB Create Document
Creating documents is the "C" in CRUD (Create, Read, Update, Delete). In MongoDB you add documents to a collection with insertOne() and insertMany(), and the collection and database are created automatically if they do not exist yet.
This tutorial covers both methods, the _id field and ObjectId, BSON data types, ordered and unordered inserts, error handling, write concern, bulkWrite(), and the same operations from Java.
1. Inserting One Document: insertOne()
use bookstore
db.books.insertOne({
title: "Practical Java Streams",
category: "Java",
price: 499,
stock: 40,
tags: ["java", "streams", "functional"]
})
// {
// acknowledged: true,
// insertedId: ObjectId('6712c0a4e1d3b8f2a9c4d5e6')
// }
The result tells you that the server acknowledged the write and which _id the new document received.
2. Inserting Many Documents: insertMany()
db.books.insertMany([
{ title: "Designing Event Systems", category: "Kafka", price: 650, stock: 12 },
{ title: "Document Modeling Basics", category: "Database", price: 420, stock: 0 },
{ title: "Cloud Native Spring", category: "Java", price: 720, stock: 25 }
])
// {
// acknowledged: true,
// insertedIds: { '0': ObjectId('...'), '1': ObjectId('...'), '2': ObjectId('...') }
// }
insertMany() sends the documents in batches, which is far faster than calling insertOne() in a loop.
3. The _id Field and ObjectId
Every document must have a unique _id in its collection; it acts as the primary key and is always indexed. If you do not provide one, the driver or shell generates an ObjectId.
An ObjectId is a 12-byte value made of:
| Bytes | Content |
|---|---|
| 4 | Creation time in seconds since the Unix epoch |
| 5 | A random value unique to the machine and process |
| 3 | An incrementing counter, starting from a random value |
Because the timestamp comes first, ObjectIds created later sort roughly after earlier ones, and you can read the creation time back:
const id = ObjectId()
id.getTimestamp() // ISODate('2026-10-18T09:41:12.000Z')
You can also supply your own _id when the data has a natural unique key, such as an ISBN, an order number or a user name:
db.books.insertOne({ _id: "978-1-4028-9462-6", title: "Reactive Patterns", price: 560 })
4. BSON Data Types
Documents are stored as BSON, which supports more types than plain JSON. Using the right type matters for sorting, range queries and correctness:
| Type | mongosh example | Use for |
|---|---|---|
| String | "Pune" | Text (UTF-8) |
| Int32 / Int64 | 40, NumberLong("9007199254740993") | Whole numbers |
| Double | 4.75 | Measurements, scores |
| Decimal128 | NumberDecimal("499.99") | Money and exact decimals |
| Boolean | true | Flags |
| Date | new Date(), ISODate("2026-10-18T00:00:00Z") | Timestamps (stored in UTC) |
| Array | ["java", "streams"] | Lists of values or documents |
| Embedded document | { city: "Pune", pin: "411001" } | Grouped fields |
| ObjectId | ObjectId() | Identifiers and references |
| Null | null | Explicitly empty values |
| Binary data | BinData(0, "..."), UUID() | Small files, hashes, UUIDs |
Date values, not strings like "18/10/2026". String dates sort alphabetically, cannot use date operators, and break range queries.5. Embedded Documents and Arrays
Related data that is read together belongs in the same document:
db.orders.insertOne({
orderNo: 5001,
customer: { id: "C-1", name: "Aditi Rao" },
items: [
{ bookId: 101, title: "Practical Java Streams", qty: 1, price: NumberDecimal("499") },
{ bookId: 103, title: "Document Modeling Basics", qty: 2, price: NumberDecimal("420") }
],
status: "PENDING",
createdAt: new Date()
})
6. Limits and Field Name Rules
- A document can be at most 16 MB, and nesting can be at most 100 levels deep.
- Field names are case-sensitive strings;
Priceandpriceare different fields. - Avoid field names that start with
$or contain.; they clash with query operators and dot notation. - The
_idvalue cannot be an array.
7. Ordered vs Unordered Inserts
By default insertMany() is ordered: it inserts documents in sequence and stops at the first error. With ordered: false, it attempts every document and reports all errors at the end, which is faster for bulk loads.
db.tags.insertMany(
[ { _id: "java" }, { _id: "java" }, { _id: "kafka" } ], // duplicate _id in the middle
{ ordered: false }
)
// MongoBulkWriteError: E11000 duplicate key error ...
// result.insertedCount: 2 <-- "kafka" was still inserted
With the default ordered: true, only "java" would have been inserted, because the operation stops at the duplicate.
8. Handling Duplicate Key Errors
Inserting a document whose _id, or any field with a unique index, already exists fails with error code 11000:
db.users.createIndex({ email: 1 }, { unique: true })
db.users.insertOne({ email: "aditi@example.com" })
try {
db.users.insertOne({ email: "aditi@example.com" })
} catch (e) {
print(e.code, e.message) // 11000 E11000 duplicate key error collection: ...
}
If you want "insert if missing, otherwise leave alone", use an update with upsert: true and $setOnInsert instead. See Update Document.
9. Write Concern
Write concern controls how many servers must confirm a write before it is reported as successful. Since MongoDB 5.0 the default on replica sets is { w: "majority" }, meaning a majority of members have the data, so it survives a primary failure.
db.payments.insertOne(
{ orderNo: 5001, amount: NumberDecimal("919.00") },
{ writeConcern: { w: "majority", wtimeout: 5000 } }
)
10. Mixed Operations with bulkWrite()
bulkWrite() sends a batch of different write operations in one request:
db.books.bulkWrite([
{ insertOne: { document: { title: "Testing Microservices", category: "Java", price: 590 } } },
{ updateOne: { filter: { title: "Cloud Native Spring" }, update: { $inc: { stock: 10 } } } },
{ deleteOne: { filter: { stock: 0, category: "Database" } } }
], { ordered: false })
11. Inserting from Java
import com.mongodb.client.*;
import com.mongodb.client.result.InsertManyResult;
import org.bson.Document;
import org.bson.types.Decimal128;
import java.math.BigDecimal;
import java.util.*;
public class InsertDocumentsExample {
public static void main(String[] args) {
try (MongoClient client = MongoClients.create("mongodb://localhost:27017")) {
MongoCollection<Document> books = client.getDatabase("bookstore").getCollection("books");
Document one = new Document("title", "Spring Data in Action")
.append("category", "Java")
.append("price", new Decimal128(new BigDecimal("549.00")))
.append("tags", List.of("spring", "data"))
.append("createdAt", new Date());
books.insertOne(one);
System.out.println("Inserted id: " + one.getObjectId("_id")); // the driver sets _id
InsertManyResult many = books.insertMany(List.of(
new Document("title", "Effective Indexing").append("price", 380),
new Document("title", "Streams and Lambdas").append("price", 410)));
System.out.println("Inserted: " + many.getInsertedIds().size());
}
}
}
With Spring Data MongoDB, you would annotate a class with @Document and call repository.save(book) or mongoTemplate.insert(book).
12. Summary
- Use
insertOne()for a single document andinsertMany()for many; both create the collection if needed. - Every document has a unique
_id; anObjectIdis generated if you do not provide one. - Choose proper BSON types: real dates,
Decimal128for money, arrays and embedded documents for related data. ordered: falsecontinues past errors; duplicate keys fail with error 11000.- Use write concern
majorityfor important data, andbulkWrite()for mixed batches.