Docs 菜单

Docs 主页开发应用程序MongoDB 驱动程序Node.js 驱动程序

更新文档中的数组

在此页面上

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

在本指南中,您可以了解如何使用以下数组更新操作符来修改嵌入在文档中的数组:

  • 位置操作符 $

  • 所有位置操作符$[]

  • 过滤后的位置操作符$[<identifier>]

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

位置运算符可指定要更新的数组元素。您可以使用这些运算符对数组中符合某一条件的第一个元素、所有元素或某些元素进行更新。

要使用位置运算符指定数组中的元素,请使用点表示法。点表示法是一种用于导航 BSON 对象的属性访问语法。要了解更多信息,请参阅点表示法。

要更新与查询匹配的每个文档的第一个数组元素,请使用位置运算符 $

位置运算符$引用与查询匹配的数组。不能使用此操作符引用嵌套数组。如果要访问嵌套数组,请使用筛选后的位置运算符。

重要

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

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

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

下面的代码展示了如何在匹配查询的第一个数组元素中使某个值增加。

该查询会匹配其中 x 值为 string 类型的 entries 数组中的元素。更新后,第一个匹配元素中的 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 },
]
}

以下代码演示如何从 date"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>] 指定更新文档中匹配的数组元素。要识别待匹配的数组元素,请将该操作符与 arrayFilters 对象中的 <identifier> 配对。

<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" 食谱。

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

要将匹配数组条目中的 quantity 值加倍,请使用过滤后的位置操作符,如以下代码中所示:

// 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);

对于匹配条件的项目,更新将用 quantity 值乘以 2。项目 "Sesame oil"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" }
]
}
← 修改文档