首页/数据/NoSQL 速查/数组操作符 $push / $pull / $addToSet
MongoDB99 条

数组操作符 $push / $pull / $addToSet

维护数组字段:$push 追加(可配 $each/$slice/$sort)、$addToSet 去重添加、$pull 按条件移除、$pop 弹出首尾元素。

NoSQL 速查数据更新于 2026-10-13

数组字段怎么改

MongoDB 文档可以内嵌数组,更新时要用专用数组操作符,而不是把整个字段重新 $set 一遍。整字段覆盖会丢掉并发写入追加的内容,数组操作符则是在单文档内做原子修改:追加、去重添加、按条件删除、截断保留。

基本信息

适用版本MongoDB 4.x-8.x / mongosh
作用对象单文档内的数组字段
常用操作符$push / $addToSet / $pop / $pull / $pullAll
修饰符$each / $slice / $sort(仅 $push 支持前三个)
所需权限readWrite

典型使用场景

  • 给文档追加标签、事件记录:$push 原子追加,不会被并发写覆盖
  • 维护白名单/黑名单:$addToSet 只在元素不存在时写入,天然去重
  • 清理失效元素:$pull 按值或条件移除,如删掉状态为 draft 的标签
  • 只保留最近 N 条:$push 配 $slice:-N,把流水类数组限制在固定长度
  • 修改数组内某个元素:定位符 $ 或 arrayFilters 精确命中,不必读改写整数组

示例

示例
db.posts.updateOne({ _id: 1 }, { $push: { tags: { $each: ["mongo", "index"], $slice: -5 } } })  # 追加并只保留最近 5 个
db.posts.updateOne({ _id: 1 }, { $addToSet: { tags: { $each: ["mongo", "db"] } } })   # 去重添加,已存在的不写
db.posts.updateOne({ _id: 1 }, { $pull: { tags: "draft" } })                          # 移除所有等于 draft 的元素
db.posts.updateOne({ _id: 1 }, { $pop: { tags: 1 } })                                  # 1 弹尾部,-1 弹头部
db.posts.updateOne({ _id: 1, "comments.id": 9 }, { $set: { "comments.$.text": "ok" } })  # 定位符改单个元素
db.orders.updateOne({ _id: 7 }, { $set: { "items.$[e].qty": 3 } }, { arrayFilters: [ { "e.sku": "A-1" } ] })

操作符对照

操作符作用注意点
$push向数组尾部追加元素可组合 $each/$slice/$sort,字段不存在时自动创建数组
$addToSet仅当元素不存在时添加只支持 $each,不支持 $slice/$sort,判等是整个元素比较
$pull移除所有匹配的元素匹配条件可写成子文档形式,不是只删第一个
$pop弹出头部或尾部一个元素1 弹尾部、-1 弹头部,方向容易记反
$pullAll按值列表批量移除只匹配完整元素值,支持不了条件表达式
数组长期无界增长会持续推高文档体积(单文档上限 16MB)并拖慢每次更新;评论、日志这类流水数据应独立成集合,数组里只保留摘要或最近若干条。
定位符 $ 命中查询条件匹配的第一个元素,适合已知下标的场景;arrayFilters 用 $[标识符] 加过滤数组,可以一次更新多个满足条件的元素(MongoDB 3.6 起支持)。
$slice 为 0 表示清空数组,负值表示从尾部保留 N 个、正值表示从头部保留 N 个;截断方向写错会直接丢掉想要的数据,改前先用 find 验证效果。

易错点

  • 用 $set 直接赋一个新数组,会覆盖掉并发写入的追加内容 → 追加场景一律用 $push/$addToSet
  • $slice 方向记反:负值从尾部保留、正值从头部保留,写错会静默截断掉业务数据
  • $pull 移除的是所有匹配元素,若只想删一个需先读出数组再精确定位
  • 无界数组增长会把文档顶到 16MB 上限并让更新越来越慢 → 用 $slice 限长或拆成独立集合
  • $addToSet 判等是整个元素比较,对象元素的字段顺序不同会被当成两个不同元素 → 用标量键去重或改成 $pull+$push 显式覆盖

数据来源与参考

  • MongoDB Manual: Array Update Operators
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌