阿里云主机折上折
  • 微信号
Current Site:Index > The insertion of documents (insertOne, insertMany)

The insertion of documents (insertOne, insertMany)

Author:Chuan Chen 阅读数:43798人阅读 分类: MongoDB

Document Insertion (insertOne, insertMany)

MongoDB provides two primary methods for document insertion: insertOne and insertMany. These methods are used to insert a single document and batch insert multiple documents, respectively, and are among the most fundamental and commonly used operations in MongoDB.

insertOne Method

The insertOne method is used to insert a single document into a collection. Its basic syntax is as follows:

db.collection.insertOne(
   <document>,
   {
      writeConcern: <document>
   }
)

Here, <document> is the document to be inserted, and writeConcern is an optional write concern level.

Basic Example

// Insert a simple user document
db.users.insertOne({
  name: "Zhang San",
  age: 28,
  email: "zhangsan@example.com",
  hobbies: ["reading", "swimming"]
});

Upon successful insertion, MongoDB returns an object containing the following information:

{
  acknowledged: true,
  insertedId: ObjectId("5f8d8a7b9d8e7b6a9d8e7b6a")
}

Auto-Generated _id Field

If the inserted document does not specify an _id field, MongoDB automatically generates a unique ObjectId as the _id:

db.products.insertOne({
  name: "Laptop",
  price: 5999,
  category: "Electronics"
});

You can also explicitly specify the _id:

db.products.insertOne({
  _id: "prod001",
  name: "Smartphone",
  price: 3999
});

Error Handling

An error is thrown when inserting a document that violates a unique index constraint:

try {
  db.users.insertOne({
    _id: "user001",
    name: "Li Si"
  });
  
  // Inserting a document with the same _id will fail
  db.users.insertOne({
    _id: "user001",
    name: "Wang Wu"
  });
} catch (e) {
  print("Insertion failed: " + e);
}

insertMany Method

The insertMany method is used to batch insert multiple documents and is more efficient than calling insertOne multiple times. Its basic syntax is as follows:

db.collection.insertMany(
   [ <document1>, <document2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>
   }
)

Basic Example

// Batch insert multiple users
db.users.insertMany([
  {
    name: "Wang Wu",
    age: 32,
    email: "wangwu@example.com"
  },
  {
    name: "Zhao Liu",
    age: 25,
    email: "zhaoliu@example.com"
  },
  {
    name: "Qian Qi",
    age: 40,
    email: "qianqi@example.com"
  }
]);

Upon successful insertion, a result similar to the following is returned:

{
  acknowledged: true,
  insertedIds: [
    ObjectId("5f8d8a7b9d8e7b6a9d8e7b6b"),
    ObjectId("5f8d8a7b9d8e7b6a9d8e7b6c"),
    ObjectId("5f8d8a7b9d8e7b6a9d8e7b6d")
  ]
}

ordered Parameter

The ordered parameter defaults to true, meaning documents are inserted in order. If one document fails to insert, subsequent documents will not be inserted:

try {
  db.users.insertMany([
    { _id: 1, name: "User1" },
    { _id: 1, name: "User1 Duplicate" }, // This will fail
    { _id: 2, name: "User2" }
  ], { ordered: true });
} catch (e) {
  print("Batch insertion error: " + e);
}

Setting ordered to false allows MongoDB to continue attempting to insert subsequent documents:

db.users.insertMany([
  { _id: 3, name: "User3" },
  { _id: 3, name: "User3 Duplicate" }, // This will fail
  { _id: 4, name: "User4" }
], { ordered: false });

Performance Considerations for Batch Insertion

For inserting large numbers of documents, insertMany is more efficient than looping insertOne. Here is a performance comparison example:

// Not recommended: Looping insertOne for 1000 documents
const start1 = new Date();
for (let i = 0; i < 1000; i++) {
  db.test.insertOne({ value: i });
}
const end1 = new Date();
print("Loop insertOne time: " + (end1 - start1) + "ms");

// Recommended: Batch insert
const start2 = new Date();
const docs = [];
for (let i = 0; i < 1000; i++) {
  docs.push({ value: i });
}
db.test.insertMany(docs);
const end2 = new Date();
print("insertMany time: " + (end2 - start2) + "ms");

Write Concern

Write concern specifies the level of acknowledgment MongoDB requires for a write operation to be considered successful. It can be specified during insertion:

// Wait for the write to be replicated to a majority of replica set members
db.products.insertOne(
  {
    name: "Bluetooth Headphones",
    price: 299
  },
  {
    writeConcern: { w: "majority", j: true, wtimeout: 5000 }
  }
);

Common write concern options include:

  • w: Number of nodes the write must propagate to
  • j: Whether to wait for journal write
  • wtimeout: Timeout in milliseconds

Practical Application Examples

Product Import in an E-Commerce System

// Get product data from an external source
const externalProducts = [
  {
    sku: "SKU1001",
    name: "Wireless Mouse",
    price: 129,
    stock: 50,
    categories: ["Electronics", "Computer Accessories"]
  },
  {
    sku: "SKU1002",
    name: "Mechanical Keyboard",
    price: 399,
    stock: 30,
    categories: ["Electronics", "Computer Accessories"]
  },
  // More products...
];

// Batch import products
try {
  const result = db.products.insertMany(externalProducts, {
    ordered: false // Continue even if some products fail to import
  });
  print(`Successfully imported ${result.insertedCount} products`);
} catch (e) {
  print(`Error during import: ${e}`);
}

User Registration System

function registerUser(userData) {
  // Validate user data
  if (!userData.username || !userData.password) {
    throw new Error("Username and password cannot be empty");
  }
  
  // Check if the username already exists
  const existingUser = db.users.findOne({ username: userData.username });
  if (existingUser) {
    throw new Error("Username already exists");
  }
  
  // Add registration timestamps
  userData.createdAt = new Date();
  userData.updatedAt = new Date();
  
  // Insert the new user
  const result = db.users.insertOne(userData);
  
  // Return the newly created user ID
  return result.insertedId;
}

// Usage example
try {
  const newUserId = registerUser({
    username: "newuser",
    password: "securepassword123",
    email: "newuser@example.com"
  });
  print(`User registered successfully, ID: ${newUserId}`);
} catch (e) {
  print(`Registration failed: ${e.message}`);
}

Performance Optimization for Insert Operations

  1. Batch Insertion: Always prefer insertMany over looping insertOne.
  2. Adjust ordered Appropriately: For non-critical data, set ordered: false to improve throughput.
  3. Disable Indexes: For one-time bulk data imports, disable indexes first and rebuild them afterward.
  4. Use Bulk Writes: For mixed operations (insert + update), consider using bulkWrite.
// Bulk write example
const bulkOps = [
  { insertOne: { document: { name: "Product A", price: 100 } } },
  { insertOne: { document: { name: "Product B", price: 200 } } },
  { updateOne: { filter: { name: "Product A" }, update: { $set: { stock: 50 } } } }
];

db.products.bulkWrite(bulkOps);

Common Issues and Solutions

Duplicate Key Error

When the _id or a unique index field of the inserted document conflicts with an existing document, a duplicate key error is thrown. Solution:

try {
  db.users.insertOne({
    _id: "user123",
    name: "Test User"
  });
} catch (e) {
  if (e.code === 11000) {
    // Handle duplicate key error
    print("User ID already exists");
    // Optionally generate a new ID and retry
    db.users.insertOne({
      _id: ObjectId(), // Auto-generate new ID
      name: "Test User"
    });
  } else {
    throw e;
  }
}

Document Size Limit

MongoDB has a 16MB limit per document. For data that may exceed this limit:

// Check document size
function getDocumentSize(doc) {
  return Object.bsonsize(doc);
}

const largeDoc = { /* Very large document */ };
if (getDocumentSize(largeDoc) > 16 * 1024 * 1024) {
  // Need to split the document or use GridFS
  print("Document too large, needs splitting");
}

Slow Insertion Speed

If insertion speed is slower than expected, consider:

  1. Checking for excessive indexes
  2. Adjusting write concern level
  3. Using larger batch inserts
  4. Considering a sharded cluster to distribute write load
// Test insertion performance with different batch sizes
function testInsertPerformance(batchSize, totalDocs) {
  const docs = [];
  for (let i = 0; i < totalDocs; i++) {
    docs.push({ value: i, data: "x".repeat(100) });
    if (docs.length >= batchSize) {
      db.perftest.insertMany(docs);
      docs.length = 0; // Clear the array
    }
  }
  if (docs.length > 0) {
    db.perftest.insertMany(docs);
  }
}

// Test different batch sizes
testInsertPerformance(100, 10000);  // Insert 100 documents at a time
testInsertPerformance(500, 10000);  // Insert 500 documents at a time
testInsertPerformance(1000, 10000); // Insert 1000 documents at a time

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.