首页 / MongoDB 入门教程 / 更新内嵌文档与数组元素

MongoDB 入门教程

更新内嵌文档与数组元素

本教程共 50 篇 · 第 25 篇 · 更新于 2026-07-30 · 约 8 分钟阅读

MongoDBMongoDB 入门教程数组元素更新位置运算符arrayFilters内嵌文档

25. 更新内嵌文档与数组元素

本节目标:学会定位并修改数组里的某个元素、内嵌文档的某个子字段,掌握位置运算符 $$[] 和带 arrayFilters$[elem]

前面章节的更新都是「整篇文档层面」的。可真实数据里,数组元素(如订单里的商品行)常常需要单独改某一个。这章专门解决「数组里的第几个、满足条件的那几个」怎么精准下手。

db.orders.insertOne({
  _id: 1001,
  user_id: 1,
  status: "pending",
  items: [
    { product: "机械键盘", qty: 1, price: 399 },
    { product: "无线鼠标", qty: 2, price: 129 },
    { product: "USB-C hub", qty: 3, price: 199 }
  ]
})

用数组下标定点改

最直白的办法:用 "数组.下标.子字段" 直接定位。下标从 0 开始:

// 把订单里第 1 个商品(机械键盘)的数量改成 5
db.orders.updateOne(
  { _id: 1001 },
  { $set: { "items.0.qty": 5 } }
)

这个写法简单,但前提是「你知道要改的是第几个」。通常你并不知道下标,那就得用下面的运算符。

位置运算符 $:改第一个匹配的元素

筛选条件里如果匹配到了数组的某个元素,$ 就代表「那个元素的位置」。更新时用 "items.$.qty" 就能改中它:

// 把订单里「机械键盘」这一行的数量改成 3
db.orders.updateOne(
  { _id: 1001, "items.product": "机械键盘" },
  { $set: { "items.$.qty": 3 } }
)
Note

$ 只代表第一个匹配到的数组元素。如果有多行都是机械键盘,只有第一行被改。

全位置运算符 $[]:改数组全部元素

想把数组里每一个元素都改一遍,用 $[](注意中括号):

// 订单里所有商品数量统统 +1
db.orders.updateOne(
  { _id: 1001 },
  { $inc: { "items.$[].qty": 1 } }
)

带条件的过滤位置 $[elem] + arrayFilters

$ 只能改第一个,$[] 会改全部。如果想「只改满足条件的那些」,就得用 $[elem](elem 是自定义标识符)配合 arrayFilters 选项。

// 把所有「数量小于 2」的商品行数量改成 10
db.orders.updateOne(
  { _id: 1001 },
  { $set: { "items.$[item].qty": 10 } },
  { arrayFilters: [ { "item.qty": { $lt: 2 } } ] }
)

这里的 item 是占位符,指代数组里「正在被检查」的每个元素。arrayFilters 里的条件决定哪些元素被选中。

Tip

标识符可以随便起名,但要以字母开头,不能和字段名冲突。常用 elem。一个更新里可以写多个 $[x]$[y],对应 arrayFilters 里的多个条件。

组合:内嵌文档子字段也能改

数组元素本身是个内嵌文档,子字段照常点号访问。下面给所有高价商品(单价 ≥ 300)打九折:

db.orders.updateOne(
  { _id: 1001 },
  { $mul: { "items.$[p].price": 0.9 } },
  { arrayFilters: [ { "p.price": { $gte: 300 } } ] }
)

四种定位方式对比

写法改哪些何时用
"items.0.qty"固定下标明确知道第几个
"items.$.qty"首个匹配的按值定位第一个
"items.$[].qty"全部元素统一改所有
"items.$[x].qty"满足条件的按条件批量改
Warning

$$[] 不能同时出现在同一条更新里。需要「带条件改多个」时必须用 $[elem] + arrayFilters。另外 $ 依赖查询筛选命中数组元素,筛选没命中数组时它会失效。

学会了精准改数组元素,下章我们讲怎么把文档删掉,以及怎么删整张集合。