Amazon DocumentDB 文档插入 #

一、文档结构 #

1.1 文档格式 #

javascript
// 基本文档结构
{
  "_id": ObjectId("65a1b2c3d4e5f67890123456"),
  "name": "张三",
  "age": 30,
  "email": "zhangsan@example.com",
  "createdAt": ISODate("2024-01-15T10:00:00Z")
}

1.2 数据类型 #

javascript
// 支持的数据类型
{
  "stringField": "文本",
  "intField": NumberInt(42),
  "longField": NumberLong(123456789),
  "doubleField": 3.14,
  "boolField": true,
  "dateField": new Date(),
  "objectIdField": ObjectId(),
  "arrayField": [1, 2, 3],
  "objectField": { key: "value" },
  "nullField": null,
  "binaryField": BinData(0, "base64string")
}

1.3 _id字段 #

javascript
// _id字段规则
// - 每个文档必须有_id
// - _id值必须唯一
// - 如果不指定,自动生成ObjectId

// 自动生成
db.users.insertOne({ name: "张三" })
// _id: ObjectId("65a1b2c3d4e5f67890123456")

// 手动指定
db.users.insertOne({
  _id: "user_001",
  name: "张三"
})

二、insertOne - 插入单个文档 #

2.1 基本用法 #

javascript
// 插入单个文档
db.users.insertOne({
  name: "张三",
  age: 30,
  email: "zhangsan@example.com",
  createdAt: new Date()
})

// 返回结果
{
  "acknowledged": true,
  "insertedId": ObjectId("65a1b2c3d4e5f67890123456")
}

2.2 带选项插入 #

javascript
// 指定写关注
db.users.insertOne(
  { name: "李四", age: 25 },
  { writeConcern: { w: "majority" } }
)

// 有序插入
db.users.insertOne(
  { name: "王五" },
  { ordered: true }
)

2.3 嵌套文档插入 #

javascript
// 插入嵌套文档
db.users.insertOne({
  name: "张三",
  address: {
    province: "北京",
    city: "北京市",
    district: "朝阳区",
    street: "朝阳路100号"
  },
  contacts: {
    phone: "13800138000",
    email: "zhangsan@example.com"
  }
})

2.4 数组字段插入 #

javascript
// 插入包含数组的文档
db.users.insertOne({
  name: "张三",
  tags: ["编程", "阅读", "游泳"],
  education: [
    { school: "清华大学", degree: "本科", year: 2015 },
    { school: "北京大学", degree: "硕士", year: 2018 }
  ],
  scores: [95, 88, 92, 85]
})

三、insertMany - 插入多个文档 #

3.1 基本用法 #

javascript
// 插入多个文档
db.users.insertMany([
  {
    name: "李四",
    age: 25,
    email: "lisi@example.com"
  },
  {
    name: "王五",
    age: 28,
    email: "wangwu@example.com"
  },
  {
    name: "赵六",
    age: 32,
    email: "zhaoliu@example.com"
  }
])

// 返回结果
{
  "acknowledged": true,
  "insertedIds": [
    ObjectId("65a1b2c3d4e5f67890123457"),
    ObjectId("65a1b2c3d4e5f67890123458"),
    ObjectId("65a1b2c3d4e5f67890123459")
  ]
}

3.2 有序与无序插入 #

javascript
// 有序插入(默认)- 遇到错误停止
db.users.insertMany(
  [
    { _id: 1, name: "用户1" },
    { _id: 1, name: "用户2" },  // 重复ID,会报错
    { _id: 2, name: "用户3" }   // 不会插入
  ],
  { ordered: true }
)

// 无序插入 - 继续插入其他文档
db.users.insertMany(
  [
    { _id: 1, name: "用户1" },
    { _id: 1, name: "用户2" },  // 失败
    { _id: 2, name: "用户3" }   // 会插入
  ],
  { ordered: false }
)

3.3 批量插入选项 #

javascript
// 完整选项
db.users.insertMany(
  [
    { name: "用户A", status: "active" },
    { name: "用户B", status: "pending" }
  ],
  {
    ordered: false,
    writeConcern: { w: "majority", wtimeout: 5000 }
  }
)

四、批量插入技巧 #

4.1 分批插入 #

javascript
// 大数据量分批插入
function batchInsert(collection, documents, batchSize = 1000) {
  for (let i = 0; i < documents.length; i += batchSize) {
    const batch = documents.slice(i, i + batchSize);
    collection.insertMany(batch, { ordered: false });
    print(`Inserted batch ${Math.floor(i / batchSize) + 1}`);
  }
}

// 使用示例
const users = [];
for (let i = 0; i < 10000; i++) {
  users.push({
    name: `用户${i}`,
    age: Math.floor(Math.random() * 50) + 18,
    createdAt: new Date()
  });
}

batchInsert(db.users, users, 1000);

4.2 使用脚本批量插入 #

javascript
// 从CSV导入
const csvData = `name,age,email
张三,30,zhangsan@example.com
李四,25,lisi@example.com
王五,28,wangwu@example.com`;

const documents = csvData.split('\n').slice(1).map(line => {
  const [name, age, email] = line.split(',');
  return {
    name,
    age: parseInt(age),
    email,
    createdAt: new Date()
  };
});

db.users.insertMany(documents);

4.3 从其他集合复制 #

javascript
// 复制数据到新集合
db.source.find().forEach(function(doc) {
  db.destination.insertOne(doc);
});

// 使用聚合管道复制
db.source.aggregate([
  { $match: { status: "active" } },
  { $out: "active_users" }
]);

五、错误处理 #

5.1 重复键错误 #

javascript
// 处理重复键错误
try {
  db.users.insertOne({
    _id: 1,
    name: "张三"
  });
} catch (error) {
  if (error.code === 11000) {
    print("文档已存在,跳过插入");
  } else {
    throw error;
  }
}

5.2 验证错误 #

javascript
// 处理验证错误
try {
  db.users.insertOne({
    name: "张三",
    email: "invalid-email"  // 不符合验证规则
  });
} catch (error) {
  if (error.code === 121) {
    print("文档验证失败: " + error.message);
  }
}

5.3 写入错误 #

javascript
// 处理写入错误
try {
  db.users.insertMany(
    [
      { _id: 1, name: "用户1" },
      { _id: 1, name: "用户2" }
    ],
    { ordered: false }
  );
} catch (error) {
  print("部分文档插入失败");
  print("成功数量: " + error.result.result.nInserted);
  print("错误详情: " + JSON.stringify(error.result.result.writeErrors));
}

六、性能优化 #

6.1 批量大小优化 #

text
批量插入建议:
├── 批量大小:1000-5000文档
├── 单批大小:不超过16MB
├── 使用无序插入提高性能
└── 监控网络和内存使用

6.2 索引影响 #

javascript
// 插入前考虑索引
// 索引会降低插入速度

// 查看索引
db.users.getIndexes()

// 大量数据导入时,可以先删除索引
db.users.dropIndexes()

// 导入后重建索引
db.users.createIndex({ email: 1 })

6.3 写关注优化 #

javascript
// 根据场景选择写关注
// 高性能场景
db.users.insertOne(
  { name: "张三" },
  { writeConcern: { w: 1 } }  // 只确认主实例
)

// 高可靠场景
db.users.insertOne(
  { name: "张三" },
  { writeConcern: { w: "majority", j: true } }
)

七、实际应用场景 #

7.1 用户注册 #

javascript
// 用户注册
async function registerUser(userData) {
  const user = {
    email: userData.email,
    password: hashPassword(userData.password),
    name: userData.name,
    status: "pending",
    createdAt: new Date(),
    updatedAt: new Date()
  };

  try {
    const result = await db.users.insertOne(user);
    return { success: true, userId: result.insertedId };
  } catch (error) {
    if (error.code === 11000) {
      return { success: false, error: "邮箱已被注册" };
    }
    throw error;
  }
}

7.2 日志记录 #

javascript
// 批量日志插入
const logBuffer = [];
const BUFFER_SIZE = 100;

function logEvent(event) {
  logBuffer.push({
    ...event,
    timestamp: new Date()
  });

  if (logBuffer.length >= BUFFER_SIZE) {
    flushLogs();
  }
}

function flushLogs() {
  if (logBuffer.length === 0) return;

  db.logs.insertMany(logBuffer, { ordered: false });
  logBuffer.length = 0;
}

// 定期刷新
setInterval(flushLogs, 5000);

7.3 数据导入 #

javascript
// 从JSON文件导入
const fs = require('fs');

function importFromJSON(filePath, collection) {
  const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
  
  const batchSize = 1000;
  for (let i = 0; i < data.length; i += batchSize) {
    const batch = data.slice(i, i + batchSize);
    collection.insertMany(batch, { ordered: false });
    print(`Imported ${Math.min(i + batchSize, data.length)} / ${data.length}`);
  }
}

importFromJSON('./users.json', db.users);

八、最佳实践 #

8.1 文档设计 #

text
设计建议:
├── 使用有意义的字段名
├── 保持字段命名一致
├── 避免过深的嵌套(建议不超过3层)
├── 考虑查询模式设计文档
└── 添加必要的索引

8.2 批量插入建议 #

text
批量插入最佳实践:
├── 使用insertMany代替循环insertOne
├── 合理设置批量大小
├── 使用无序插入提高性能
├── 处理错误和重试
└── 监控性能指标

8.3 错误处理建议 #

text
错误处理最佳实践:
├── 捕获并处理重复键错误
├── 处理验证错误
├── 记录失败文档
├── 实现重试机制
└── 监控错误率

九、总结 #

9.1 插入方法对比 #

方法 用途 特点
insertOne 插入单个文档 简单直接
insertMany 插入多个文档 批量高效
bulkWrite 批量混合操作 灵活强大

9.2 关键要点 #

text
插入操作要点:
├── 理解_id字段的作用
├── 选择合适的批量大小
├── 处理可能的错误
├── 优化写关注设置
└── 监控插入性能

下一步,让我们学习文档更新!

最后更新:2026-03-27