Update Arrays in a Document更新文档中的数组

If you need to modify an array embedded within a document, you can use an array update operator in your update method call. 如果需要修改文档中嵌入的数组,可以在更新方法调用中使用数组更新运算符。In this guide, we explain and show examples on usage of these operators including:在本指南中,我们解释并展示了这些运算符的使用示例,包括:

See the MongoDB server guide on Update Operators for a complete list.有关完整列表,请参阅《MongoDB服务器指南》中的更新运算符

The following examples use a database called test and collection called pizza which contains documents that describe customers and their pizza shop orders as array elements in field called items. 以下示例使用名为test的数据库和名为pizza的集合,该数据库包含将客户及其比萨饼店订单描述为字段items中的数组元素的文档。Use the following sample document to follow the example queries:使用以下示例文档执行示例查询:

[{
   name: "Steve Lobsters",
   address: "731 Yexington Avenue",
   items: [
     {
       type: "beverage",
       name: "Water",
       size: "17oz"
     },
     {
       type: "pizza",
       size: "large",
       toppings: ["pepperoni"],
     },
     {
       type: "pizza",
       size: "medium",
       toppings: ["mushrooms", "sausage", "green peppers"],
       comment: "Extra green peppers please!",
     },
     {
       type: "pizza",
       size: "large",
       toppings: ["pineapple, ham"],
       comment: "red pepper flakes on top",
     },
     {
       type: "calzone",
       fillings: ["canadian bacon", "sausage", "onion"],
     },
     {
       type: "beverage",
       name: "Diet Pepsi",
       size: "16oz",
     },
   ],
 },
 {
   name: "Popeye",
   address: "1 Sweethaven",
   items: [
     {
       type: "pizza",
       size: "large",
       toppings: ["garlic, spinach"],
     },
     {
       type: "calzone",
       toppings: ["ham"],
     },
   ],
 }]

To perform the update on only the first array element of each document that matches your query document in your update operation, use the $ positional array update operator. 要在更新操作中仅对与查询文档匹配的每个文档的第一个数组元素执行更新,请使用$条件数组更新运算符。This update operator references the array matched by the query filter and cannot be used to reference an array nested within that array. 此更新运算符引用查询筛选器匹配的数组,不能用于引用嵌套在该数组中的数组。For cases in which you need to access the nested arrays, use the filtered positional operator.对于需要访问嵌套阵列的情况,请使用筛选的位置运算符

The following code snippet shows how you can use the $ array update operator to update the size of the first pizza order item to "extra large" for the customer named "Steve Lobsters".下面的代码片段显示了如何使用$数组更新运算符将名为“Steve Lobsters”的客户的第一个比萨饼订单项目的大小更新为“extra large”。

    const query = { name: "Steve Lobsters", "items.type": "pizza" };
    const updateDocument = {
      $set: { "items.$.size": "extra large" }
    };
    const result = await pizza.updateOne(query, updateDocument);

Once the update operation is run, the document contains the new value for size for the first item:运行更新操作后,文档将包含第一个项目的新大小值:

{
  name: "Steve Lobsters",
  ...
  items: [
    {
      type: "pizza",
      size: "extra large",
      ...
}

The query filter matches all documents that contain an element embedded in the items array that contain a value of pizza in the type field. 查询筛选器匹配所有文档,这些文档包含嵌入在items数组中的元素,该数组在type字段中包含值pizzaThe updateDocument specifies the update operation should set the first array element match in items to "extra large".updateDocument指定更新操作应将items中的第一个数组元素匹配设置为“extra large”。

Note that we included both name and items.type fields in the query filter in order to match the array in which we apply the $ operator. 请注意,我们在查询筛选器中同时包含nameitems.type字段,以便与应用$运算符的数组相匹配。If we omit the items.type field from the query and specify the $ operator in our update, we encounter the following error:如果在查询中省略items.type字段,并在更新中指定$运算符,则会遇到以下错误:

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

Do not use the $ operator in an upsert call because the $ is treated as a field name in the insert document.upsert调用中不要使用$运算符,因为在插入文档中,$被视为字段名。

To perform the update on all of the array elements of each document that matches your query document in your update operation, use the all positional operator, $[].要在更新操作中对与查询文档匹配的每个文档的所有数组元素执行更新,请使用“全部位置”运算符$[]

The following code snippet shows how you can use the $[] array update operator to add "fresh mozzarella" to the toppings of all of Popeye's order items.下面的代码片段显示了如何使用$[]数组更新操作符将“fresh mozzarella”添加到Popeye所有订单项目的配料。

    const query = { "name": "Popeye" };
    const updateDocument = {
      $push: { "items.$[].toppings": "fresh mozzarella" }
    };
    const result = await pizza.updateOne(query, updateDocument);

After you run the update method, your customer document for "Popeye" should resemble the following:运行更新方法后,“Popeye”的客户文档应类似于以下内容:

{
  "name":"Popeye",
  ...
  "items": [
    {
      "type": "pizza",
      ...
      "toppings": ["garlic", "spinach", "fresh mozzarella"],
    },
    {
      "type": "calzone",
      ...
      "toppings":["ham", "fresh mozzarella"],
    },
  ]
}

In the previous sections, we used the $ operator to match the first array element and the $[] operator to match all array elements. 在前面的部分中,我们使用$运算符匹配第一个数组元素,使用$[]运算符匹配所有数组元素。In this section, we use the filtered positional operator to match all embedded array elements that match our specified criteria.在本节中,我们使用筛选的位置运算符来匹配与指定条件匹配的所有嵌入数组元素。

The filtered positional operator, denoted by $[<identifier>], specifies the matching array elements in the update document. 过滤后的位置运算符由$[<identifier>]表示,用于指定更新文档中匹配的数组元素。This operator is paired with query filters in an arrayFilters object in your update operation's options parameter to identify which array elements to match.此运算符与更新操作的options参数中arrayFilters对象中的查询筛选器配对,以标识要匹配的数组元素。

The <identifier> term is a placeholder value you designate that represents an element of the array field name that prefixes it. 这个<identifier>术语是您指定的占位符值,表示作为其前缀的数组字段名的元素。For example, to add a "garlic" topping to certain order items using this operator, format your update document as follows:例如,要使用此运算符将“大蒜”配料添加到某些订单项目,请按如下格式设置更新文档:

{ $push: { items.$[orderItem].toppings: "garlic" } }
Note

The <identifier> placeholder name must start with lowercase and contain only alphanumeric characters.这个<identifier>占位符名称必须以小写字母开头,并且仅包含字母数字字符。

This update document specifies the following:此更新文档指定了以下内容:

  • $push: the update operator:更新运算符
  • items: the array in the document to update:要更新的文档中的数组
  • orderItem: the identifier for the filtered positional operator:已筛选位置运算符的标识符
  • toppings: the field on the items array element to update:要更新的items数组元素上的字段
  • garlic: the value to push onto the toppings array:要推送到toppings(配料)数组上的值

Next, add the matching criteria in your arrayFilters object in your update operation's options parameter. 接下来,在更新操作的选项参数中的arrayFilters对象中添加匹配条件。This object is an array of query filters that specify which array elements to include in the update. 此对象是一个查询筛选器数组,用于指定更新中要包含的数组元素。To add the "garlic" topping to order items of type "pizza" and "large size", pass the following arrayFilters:要在订购的“比萨饼”和“大号”项目中添加“大蒜”配料,请通过以下arrayFilters

arrayFilters: [
  { orderItem.type: "pizza" },
  { orderItem.size: "large" }
]

The following snippet shows the complete update method for this example:以下代码段显示了此示例的完整更新方法:

    const query = { name: "Steve Lobsters" };
    const updateDocument = {
      $push: { "items.$[orderItem].toppings": "garlic" }
    };
    const options = {
      arrayFilters: [{
        "orderItem.type": "pizza",
        "orderItem.size": "large",
      }]
    };
const result = await pizza.updateMany(query, updateDocument, options);

After we run the method above, all of the large pizza order items for customer "Steve Lobsters" now contain "garlic" in the toppings field:在我们运行上述方法后,客户“Steve Lobsters”的所有大型比萨饼订单项目现在都在toppings(配料)字段中包含“大蒜”:

{
  name: "Steve Lobsters",
  ...
  items: [
    {
      type: "pizza",
      size: "large",
      toppings: ["pepperoni", "garlic"]
    },
    {
      type: "pizza",
      size: "large",
      toppings: ["pineapple", "ham", "garlic"]
      ...
}

Let's run through another example. 让我们来看另一个例子。Suppose "Steve Lobsters" wants to adjust their order to add "salami" as a topping to only the large pepperoni pizza, you can use the filtered positional operator to perform the update as follows:假设“Steve Lobsters”想要调整他们的顺序,只将“salami”添加到大意大利香肠比萨的配料,您可以使用过滤的位置操作符执行更新,如下所示:

    const query = { name: "Steve Lobsters" };
    const updateDocument = {
      $push: { "items.$[item].toppings": "salami" },
    };
    const options = {
      arrayFilters: [
        {
          "item.type": "pizza",
          "item.toppings": "pepperoni",
        },
      ],
    };
    const result = await pizza.updateOne(query, updateDocument, options);

After we run the update method, the document resembles the following:运行update方法后,文档类似于以下内容:

{
  name: "Steve Lobsters",
  address: "731 Yexington Avenue",
  items: [
    {
      type: "pizza",
      size: "large",
      toppings: ["pepperoni", "salami"],
    },
    {
      type: "pizza",
      size: "medium",
      toppings: ["mushrooms", "sausage", "green peppers"],
      comment: "Extra green peppers please!",
    },
    {
      type: "pizza",
      size: "large",
      toppings: ["pineapple, ham"],
      comment: "red pepper flakes on top",
    },
    {
      type: "calzone",
      fillings: ["canadian bacon", "sausage", "onion"],
    },
    {
      type: "beverage",
      name: "Diet Pepsi",
      size: "16oz",
    },
  ],
}