00:00

MongoDB Create Document

Last updated:

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()

mongosh
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()

mongosh
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:

BytesContent
4Creation time in seconds since the Unix epoch
5A random value unique to the machine and process
3An 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:

mongosh
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:

mongosh
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:

Typemongosh exampleUse for
String"Pune"Text (UTF-8)
Int32 / Int6440, NumberLong("9007199254740993")Whole numbers
Double4.75Measurements, scores
Decimal128NumberDecimal("499.99")Money and exact decimals
BooleantrueFlags
Datenew 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
ObjectIdObjectId()Identifiers and references
NullnullExplicitly empty values
Binary dataBinData(0, "..."), UUID()Small files, hashes, UUIDs
Store dates as real 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:

mongosh
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; Price and price are different fields.
  • Avoid field names that start with $ or contain .; they clash with query operators and dot notation.
  • The _id value 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.

mongosh
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:

mongosh
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.

mongosh
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:

mongosh
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

InsertDocumentsExample.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 and insertMany() for many; both create the collection if needed.
  • Every document has a unique _id; an ObjectId is generated if you do not provide one.
  • Choose proper BSON types: real dates, Decimal128 for money, arrays and embedded documents for related data.
  • ordered: false continues past errors; duplicate keys fail with error 11000.
  • Use write concern majority for important data, and bulkWrite() for mixed batches.