0Pricing
MongoDB Academy · 课时

insertOne 与 insertMany

您将插入单个文档和批量文档,并检查每次操作返回的自动生成 _id 字段。

insertOne 与 insertMany 是 CoddyKit 上的免费 MongoDB Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 MongoDB Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 MongoDB Academy 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

The Two Insert Methods

MongoDB provides two methods for adding documents to a collection:

  • insertOne(doc) — inserts a single document and returns an object with acknowledged and insertedId
  • insertMany(docs) — inserts an array of documents and returns acknowledged and insertedIds (an object mapping array index to generated _id)

Both methods are synchronous in mongosh and return Promises in Node.js driver code. Always await them in async Node.js functions to handle errors properly.

// insertOne
const res1 = await db.collection('users').insertOne({ name: 'Alice', age: 28 });
console.log(res1.insertedId); // ObjectId('...')

// insertMany
const res2 = await db.collection('users').insertMany([
  { name: 'Bob', age: 32 },
  { name: 'Carol', age: 25 }
]);
console.log(res2.insertedIds);
// { '0': ObjectId('...'), '1': ObjectId('...') }

Auto-Generated ObjectId

When you insert a document without an _id field, MongoDB generates an ObjectId automatically. The ObjectId is a 12-byte BSON type whose structure ensures global uniqueness across distributed nodes without a central counter:

  • Bytes 0-3: Unix timestamp (seconds) — allows approximate sort by insertion time
  • Bytes 4-8: Random value (generated once per process)
  • Bytes 9-11: Incrementing counter (initialized to a random value)

This design means two different servers inserting documents at the same millisecond will still produce different ObjectIds, making distributed inserts collision-free.

// Auto-generated ObjectId on insert
db.items.insertOne({ name: 'Widget' });
// { acknowledged: true, insertedId: ObjectId('64a2f3b1c9e7e12345678901') }

// Extract timestamp from an ObjectId
const id = ObjectId('64a2f3b1c9e7e12345678901');
print(id.getTimestamp());
// ISODate('2023-07-03T10:15:29.000Z')

// Sorting by _id gives approximate insertion order
db.items.find({}).sort({ _id: 1 });

Supplying Your Own _id

You can override the auto-generated ObjectId by providing your own _id value. Any BSON type works: string, number, UUID, or even a nested object. The only requirement is that the value must be unique within the collection.

Custom _ids are useful when you already have a natural unique key—a product SKU, a username slug, or an external system's ID. However, avoid monotonically incrementing integers as custom _ids in sharded clusters—they create write hot spots on the shard that holds the highest key range.

// String _id (natural key)
db.products.insertOne({
  _id: 'SKU-WH-BLK-42',
  name: 'Wireless Headphones Black',
  price: 79.99
});

// Number _id
db.categories.insertOne({ _id: 100, name: 'Electronics' });

// Duplicate _id throws E11000 duplicate key error:
db.categories.insertOne({ _id: 100, name: 'Gadgets' });
// MongoServerError: E11000 duplicate key error

insertMany: Bulk Inserts

insertMany accepts an array of documents. It is significantly more efficient than calling insertOne in a loop because it sends all documents in a single network round-trip and MongoDB can batch the writes internally.

By default, insertMany inserts documents in ordered mode: if one document fails validation or has a duplicate _id, the operation stops and does not insert remaining documents. Set { ordered: false } as the second argument to switch to unordered mode, where MongoDB continues inserting the rest even if some fail.

// Ordered insertMany (default) - stops on first error
db.users.insertMany([
  { name: 'Alice' },
  { name: 'Bob' },
  { name: 'Carol' }
]);

// Unordered insertMany - continues after errors
db.users.insertMany(
  [
    { _id: 1, name: 'Alice' },
    { _id: 1, name: 'Duplicate' },  // Will fail (dup key)
    { _id: 2, name: 'Bob' }         // Still inserted in unordered mode
  ],
  { ordered: false }
);

Inspecting the insertedIds Object

The result object from insertMany contains insertedIds as an object (not an array) where keys are the array index strings and values are the generated ObjectIds. This lets you correlate each input document with its resulting _id.

In Node.js, you often map the inserted documents back to their IDs for further processing—for example, creating related documents in another collection that reference these new _ids.

const docs = [
  { name: 'Widget A', price: 10 },
  { name: 'Widget B', price: 20 },
  { name: 'Widget C', price: 30 }
];

const result = await db.collection('products').insertMany(docs);

console.log(result.insertedCount); // 3
console.log(result.insertedIds);
// {
//   '0': ObjectId('...'),
//   '1': ObjectId('...'),
//   '2': ObjectId('...')
// }

// Attach _ids back to original docs
docs.forEach((doc, i) => {
  doc._id = result.insertedIds[i];
});

WriteConcern: Controlling Durability

By default, insertOne and insertMany use the connection's default write concern—usually w: 1, meaning the primary acknowledges the write. You can override this per-operation:

  • { w: 0 } — fire-and-forget, no acknowledgment (fastest, unsafe)
  • { w: 1 } — acknowledged by primary (default)
  • { w: 'majority' } — acknowledged by majority of replica set members (safest)
  • { j: true } — additionally requires the write to be flushed to the journal on disk
// Safe insert: confirmed by majority of replica set + journaled
await db.collection('orders').insertOne(
  { orderId: 'ORD-001', total: 99.99, status: 'pending' },
  { writeConcern: { w: 'majority', j: true } }
);
// Slower than w:1 but guaranteed durable even if primary crashes

Handling Duplicate Key Errors

MongoDB throws a duplicate key error (E11000) when an insert violates a unique index—most commonly the _id uniqueness requirement, but also any user-defined unique index. In Node.js, this throws a MongoServerError with code 11000.

Always wrap inserts in try/catch when duplicate key errors are expected (e.g., upserting users by email). Check the error code to distinguish duplicates from other write errors and respond appropriately—return 409 Conflict from an API, or update the existing document instead.

try {
  await db.collection('users').insertOne({
    email: 'alice@example.com',
    name: 'Alice'
  });
} catch (err) {
  if (err.code === 11000) {
    // Duplicate key - email already exists
    console.log('User with this email already exists');
    // Respond with HTTP 409 Conflict in an API
  } else {
    throw err;  // Re-throw unexpected errors
  }
}

Seeding Test Data With Loops

A common development task is seeding a collection with realistic test data. You can do this directly in mongosh using a JavaScript loop, or write a Node.js script. For large datasets, use insertMany in batches of 500-1000 documents rather than one massive array—this avoids memory issues and allows progress monitoring.

For generating realistic fake data in Node.js, the @faker-js/faker library is widely used. It generates realistic names, emails, addresses, dates, and many other field types, making test data indistinguishable from real data.

// Seed 100 test users in mongosh
const users = [];
for (let i = 1; i <= 100; i++) {
  users.push({
    name: 'User ' + i,
    email: 'user' + i + '@example.com',
    age: 18 + (i % 50),
    active: i % 3 !== 0,
    createdAt: new Date(Date.now() - i * 86400000)
  });
}
db.users.insertMany(users);
// { acknowledged: true, insertedCount: 100 }

Checking Inserted Documents

After an insert, always verify your data landed correctly. Useful verification commands:

  • db.collection.countDocuments({}) — total count
  • db.collection.findOne({ _id: insertedId }) — verify a specific document by its returned _id
  • db.collection.find({}).sort({ _id: -1 }).limit(5) — see the 5 most recently inserted documents

In automated tests, verify not just that the insert succeeded (no error thrown) but also that the stored document has the expected field values—subtle type coercions or middleware transformations can change fields during insert.

// Insert and immediately verify
const { insertedId } = await db.collection('orders').insertOne({
  customerId: ObjectId('...'),
  items: [{ sku: 'A1', qty: 2 }],
  total: 39.98,
  status: 'pending'
});

const stored = await db.collection('orders').findOne({ _id: insertedId });
console.log(stored.status);   // 'pending'
console.log(stored.total);    // 39.98

Transactions and Multiple Inserts

When you need to insert documents into multiple collections atomically—all succeed or all fail together—use a multi-document transaction. Without a transaction, if the second insert fails after the first succeeds, your data is in an inconsistent state.

Transactions add latency and should be reserved for cases where atomicity is truly required. For most single-collection bulk inserts, insertMany with ordered mode provides sufficient atomicity at the collection level (either all documents before the failure are inserted, or none if rollback is needed).

// Atomic insert across two collections using a transaction
const session = client.startSession();
try {
  await session.withTransaction(async () => {
    await db.collection('orders').insertOne(
      { total: 99.99, customerId: custId }, { session }
    );
    await db.collection('orderEvents').insertOne(
      { type: 'created', orderId: ordId }, { session }
    );
  });
} finally {
  await session.endSession();
}

Performance Tip: Bulk Write API

For mixed operations (inserts, updates, deletes) in a single batch, use db.collection.bulkWrite(operations). This is more efficient than separate insertMany + updateMany calls because all operations share a single network round-trip.

Each operation in the array is an object with a key like insertOne, updateOne, deleteOne, etc. The result object summarizes inserted, modified, and deleted counts. bulkWrite also supports ordered/unordered modes just like insertMany.

await db.collection('products').bulkWrite([
  { insertOne: { document: { name: 'New Product', price: 25 } } },
  { updateOne: {
      filter: { name: 'Old Product' },
      update: { $set: { price: 15 } }
  }},
  { deleteOne: { filter: { name: 'Discontinued' } } }
]);
// { insertedCount: 1, modifiedCount: 1, deletedCount: 1 }

Quick Check

Test your understanding of MongoDB & NoSQL Databases concepts from this lesson.

Lesson Recap

In this lesson you learned: insertOne and insertMany are the two insert methods—insertMany is more efficient for bulk data and supports ordered/unordered error handling, ObjectId is auto-generated if you do not supply _id, encoding the insertion timestamp in its first 4 bytes for approximate ordering, and write concern controls durability from fire-and-forget (w:0) to majority-replicated (w:'majority'). Next up we explore the find() cursor in depth and learn how to query nested fields and arrays with dot notation.

常见问题解答

「insertOne 与 insertMany」课时是免费的吗?

是的 — 「insertOne 与 insertMany」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 MongoDB Academy 课程的其余内容,请升级到 CoddyKit PRO。 MongoDB Academy 课程共包含 4 节课。

「insertOne 与 insertMany」这节课中我会学到什么?

您将插入单个文档和批量文档,并检查每次操作返回的自动生成 _id 字段。 你通过在浏览器中直接运行的动手代码来练习 MongoDB Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 MongoDB Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 MongoDB Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「insertOne 与 insertMany」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 MongoDB Academy 课中编写并运行代码吗?

能。每节 MongoDB Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. insertOne 与 insertMany
  2. findOne 与 find:理解游标
  3. 查询嵌套字段与数组
  4. 使用 Node.js 驱动读取文档
← 返回 MongoDB Academy