Docs Menu

Update Arrays in a Document

On this page

  • Overview
  • Sample Documents
  • Match the First Array Element
  • Match All Array Elements
  • Filtered Positional Operator

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:

  • First array element match positional operator: $
  • All array element match operator: $[]
  • Filtered positional operator: $[<identifier>]

See the MongoDB server guide on Update Operators for a complete list.

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. 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".

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. The updateDocument specifies the update operation should set the first array element match in items to "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. If we omit the items.type field from the query and specify the $ operator in our update, we encounter the following error:

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.

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.

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:

{
"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. 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.

The <identifier> term is a placeholder value you designate that represents an element of the array field name that prefixes it. 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.

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
  • garlic: the value to push onto the toppings array

Next, add the matching criteria in your arrayFilters object in your update operation's options parameter. 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: [
{ 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:

{
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:

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:

{
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",
},
],
}
Give Feedback
© 2021 MongoDB, Inc.

About

  • Careers
  • Legal Notices
  • Privacy Notices
  • Security Information
  • Trust Center
© 2021 MongoDB, Inc.