文档菜单
文档首页
/ / /
Node.js 驱动
/ / /

在文档中更新数组

本页内容

  • 概述
  • 指定数组元素
  • 第一个匹配的数组元素
  • 匹配所有数组元素
  • 匹配多个数组元素

在本指南中,您可以学习如何使用以下数组更新运算符来修改文档中嵌入的数组

  • 位置运算符: $

  • 全部位置运算符$[]

  • 过滤位置运算符$[<identifier>]

有关数组更新运算符的列表,请参阅服务器手册文档中的更新运算符

位置操作符用于指定要更新的数组元素。您可以使用这些操作符对数组的第一元素、所有元素或满足特定条件的元素进行更新。

使用位置操作符指定数组中的元素,请使用点表示法。点表示法是用于导航BSON对象的属性访问语法。有关更多信息,请参阅点表示法。

要更新符合查询条件的每个文档的第一个数组元素,请使用位置操作符 $

位置操作符 $ 引用由查询匹配的数组。您不能使用此操作符来引用嵌套数组。如果需要访问嵌套数组,请使用过滤位置操作符。

重要

不要在 upsert 调用中使用 $ 操作符,因为驱动程序将 $ 视为插入文档中的字段名。

此示例使用以下示例文档来显示如何更新第一个匹配的数组元素

{
_id: ...,
entries: [
{ x: false, y: 1 },
{ x: "hello", y: 100 },
{ x: "goodbye", y: 1000 }
]
}

以下代码显示了如何增加符合查询的第一个数组元素的值。

查询匹配 entries 数组中的元素,其中 x 的值为 string 类型。更新在第一个匹配元素中将 y 值增加 33

// Query for all elements in entries array where the value of x is a string
const query = { "entries.x": { $type : "string" } };
// On first matched element, increase value of y by 33
const updateDocument = {
$inc: { "entries.$.y": 33 }
};
// Execute the update operation
const result = await myColl.updateOne(query, updateDocument);

运行更新操作后,文档将类似于以下内容

{
_id: ...,
entries: [
{ x: false, y: 1 },
{ x: "hello", y: 133 },
{ x: "goodbye", y: 1000 }
]
}

示例中在查询中包含了 entries.x 字段,以匹配 $ 操作符应用更新操作的数组。如果您在使用 $ 操作符进行更新时省略了 entries.x 字段,则驱动程序无法识别匹配的数组并引发以下错误

MongoServerError: The positional operator did not find the match needed from the query.

要更新匹配您查询的每个文档的所有数组元素,请使用所有位置操作符 $[]

以下示例使用以下示例文档,这些文档描述了电话记录,以展示如何更新所有匹配的数组元素

{
_id: ...,
date: "5/15/2023",
calls: [
{ time: "10:08 AM", caller: "Mom", duration: 67 },
{ time: "04:11 PM", caller: "Dad", duration: 121 },
{ time: "06:36 PM", caller: "Grandpa", duration: 13 }
]
},
{
_id: ...,
date: "5/16/2023",
calls: [
{ time: "11:47 AM", caller: "Mom", duration: 4 },
]
}

以下代码展示了如何从日期为 "5/15/2023" 的文档中删除 calls 数组中所有条目的 duration 字段

// Query for all documents where date is the string "5/15/2023"
const query = { date: "5/15/2023" };
// For each matched document, remove duration field from all entries in calls array
const updateDocument = {
$unset: { "calls.$[].duration": "" }
};
// Execute the update operation
const result = await myColl.updateOne(query, updateDocument);

运行更新操作后,文档将类似于以下内容

{
_id: ...,
date: "5/15/2023",
calls: [
{ time: "10:08 AM", caller: "Mom" },
{ time: "04:11 PM", caller: "Dad" },
{ time: "06:36 PM", caller: "Grandpa" }
]
},
{
_id: ...,
date: "5/16/2023",
calls: [
{ time: "11:47 AM", caller: "Mom", duration: 4 },
]
}

要对匹配查询的每个文档的所有嵌入数组元素执行更新,请使用过滤位置操作符 $[<identifier>]

过滤位置操作符 $[<identifier>] 指定更新文档中匹配的数组元素。要标识要匹配的数组元素,请将此操作符与 <identifier> 配对,在 arrayFilters 对象中使用。

<identifier> 占位符表示数组字段的元素。您必须为 <identifier> 选择一个以小写字母开头且只包含字母数字字符的值。

您可以在更新操作中使用过滤位置操作符。更新操作接受查询、更新文档和可选的选项对象作为参数。

以下步骤描述了如何在更新操作中使用过滤位置操作符

  1. 按照以下格式格式化您的更新文档

    { $<operator>: { "<array>.$[<identifier>].<arrayField>": <updateParameter> } }

    此更新文档包含以下占位符

    • $<operator>:数组更新操作符

    • <array>:要更新的文档中的数组

    • <identifier>:过滤位置操作符的标识符

    • <arrayField>:要更新的 <array> 数组元素的字段

    • <updateParameter>:描述更新的值

  2. arrayFilters 对象中添加匹配条件。此对象是一个查询数组,指定哪些数组元素应包含在更新中。在 options 参数中设置此对象

    arrayFilters: [
    { "<identifier>.<arrayField1>": <updateParameter1> },
    { "<identifier>.<arrayField2>": <updateParameter2> },
    ...
    ]
  3. 将查询、更新文档和选项传递给更新方法。以下示例代码显示了如何使用这些参数调用 updateOne() 方法

    await myColl.updateOne(query, updateDocument, options);

此示例使用以下示例文档(描述特定食谱的购物清单)来展示如何更新某些匹配的数组元素

{
_id: ...,
date: "11/12/2023",
items: [
{ item: "Scallions", quantity: 3, recipe: "Fried rice" },
{ item: "Mangos", quantity: 4, recipe: "Salsa" },
{ item: "Pork shoulder", quantity: 1, recipe: "Fried rice" },
{ item: "Sesame oil", quantity: 1, recipe: "Fried rice" }
]
},
{
_id: ...,
date: "11/20/2023",
items: [
{ item: "Coffee beans", quantity: 1, recipe: "Coffee" }
]
}

假设您想增加您在 "11/12/2023" 购物之旅中为食谱购买的商品数量。如果项目满足以下所有条件,则将其数量加倍

  • 该商品是为 "Fried rice" 食谱的。

  • 项目名称不包含单词"油"

要将匹配数组条目的数量值加倍,请使用以下代码中所示的过滤位置运算符

// Query for all documents where date is the string "11/12/2023"
const query = { date: "11/12/2023" };
// For each matched document, change the quantity of items to 2
const updateDocument = {
$mul: { "items.$[i].quantity": 2 }
};
// Update only non-oil items used for fried rice
const options = {
arrayFilters: [
{
"i.recipe": "Fried rice",
"i.item": { $not: { $regex: "oil" } },
}
]
};
// Execute the update operation
const result = await myColl.updateOne(query, updateDocument, options);

更新操作将匹配条件的项目的数量值乘以2。项目"芝麻油"arrayFilters对象中不符合条件,因此被排除在更新之外。以下文档反映了这些更改

{
_id: ...,
date: "11/12/2023",
items: [
{ item: "Scallions", quantity: 6, recipe: "Fried rice" },
{ item: "Mangos", quantity: 4, recipe: "Salsa" },
{ item: "Pork shoulder", quantity: 2, recipe: "Fried rice" },
{ item: "Sesame oil", quantity: 1, recipe: "Fried rice" }
]
},
{
_id: ...,
date: "11/20/2023",
items: [
{ item: "Coffee beans", quantity: 1, recipe: "Coffee" }
]
}

返回

修改