insert 是什么
insertOne / insertMany 是 MongoDB 的写入入口:向集合插入单条或多条 BSON 文档。insertMany 默认有序写入(ordered: true),遇到一条失败就中断后续;传 ordered: false 时跳过失败项继续写完其余文档。集合不存在时首次插入会自动建集合,返回体给出 insertedId 或 insertedIds 映射,失败明细在 writeErrors 里。
基本信息
| 方法 | db.collection.insertOne / insertMany |
|---|---|
| 批量选项 | ordered 默认 true,false 时遇错继续 |
| 返回 | insertedId 或 insertedIds,失败含 writeErrors |
| 单文档上限 | 16MB(BSON 对象编码后大小) |
| 写关注 | writeConcern: { w: "majority", j: true } 控制确认级别 |
| 集合创建 | 目标集合不存在时自动创建 |
典型使用场景
- 业务写入:新订单、新用户、新工单等文档落库
- 初始化种子数据与测试数据,一次灌入几百条
- 批量回补历史数据,用 ordered: false 尽量多写成功
- 日志类写入按日期分集合,就近写入减少冲突
- 外部数据迁移:把 CSV/JSON 转成 BSON 后批量导入
- 配合唯一索引做幂等写入,重复键错误码可识别并跳过
写入示例
写入示例
db.orders.insertOne({ _id: 1001, sku: "A-1", qty: 2, status: "paid", ts: new Date() })
db.orders.insertMany([{ sku: "A-2", qty: 1 }, { sku: "A-3", qty: 5 }], { ordered: false })
try { db.orders.insertOne({ _id: 1001, sku: "dup" }) } # 重复 _id 抛 11000
try {} catch (e) { print(e.code + " " + e.message) } # 捕获并记录错误码
db.orders.insertOne({ sku: "A-9" }, { writeConcern: { w: "majority" } }) # 提高确认级别返回字段读法
| 字段 | 含义 | 异常表现 |
|---|---|---|
| acknowledged | 写入是否被确认 | 为 false 时不能确认落库 |
| insertedId | insertOne 生成或指定的 _id | 缺失说明未写入 |
| insertedIds | insertMany 的序号到 _id 映射 | 无序写入时只含成功项 |
| writeErrors | 失败项序号与错误信息 | 出现即需按序对账补写 |
ordered: false 的批量写入部分失败不回滚,必须按 writeErrors 与 insertedIds 对账补数,否则会静默丢数据。
单文档上限 16MB 是硬限制,数组无界增长的文档迟早撞线;评论、日志这类无界列表应拆成独立集合并建立合适索引。
写入实践要点
- 批量条数按几百到几千控制,过大单批失败后重试成本高
- 只写必要字段,冗余字段会放大存储与索引体积
- 给安全关键数据加唯一索引,让重复写入直接失败而不是产生脏数据
- 高写入场景避免每条都写同一个自增热点字段,容易造成写冲突
- 写入时间字段统一用 Date 类型,字符串日期后续范围查询会失真
性能与一致性要点
- ordered: true 保证顺序但一处失败即停,批量导入优先 ordered: false 提高成功率
- 驱动会按上限自动拆批,单条文档越大每批装得越少
- 提高写关注(w: majority)能降低回滚丢数据风险,代价是写入延迟上升
- 尽量避开同一文档的高频热点更新,可减少写冲突
- 索引越多单条写入越慢,先确认是否真需要每个索引
- 持续高吞吐靠控制并发与批量节奏,而不是把单次批量堆得更大
写入返回 acknowledged 为 true 只说明按写关注被确认;立刻在从节点查询可能还看不到新数据,那是复制延迟而不是数据丢失。
upsert 可做「有则更新、无则插入」的幂等写入:updateOne 传 { upsert: true };并发下可能撞出重复键错误,应用侧需要捕获并重试。
导入外部数据前先用少量样本验证字段类型与时间格式,批量写坏之后再清理的成本远高于提前校验。
写入问题排查
- 写入慢先看索引数量与写关注级别,其次看是否集中更新同一文档
- 报 duplicate key 是唯一索引冲突,按错误里的 keyValue 定位重复值
- 报文档过大说明单条超过 16MB,需要拆分结构或改用 GridFS
- 写入成功却查不到:确认是否写到了另一个库或集合,以及是否读的从节点
- 批量部分失败:按 writeErrors 里的序号回到原始数组补写
- 导入前后核对文档数量,数量对不上优先怀疑失败项被忽略