Update Arrays in a Document
On this page
Overview
In this guide, you can learn how to use the following array update operators to modify an array embedded within a document:
- Positional Operator:
$
- All Positional Operator:
$[]
- Filtered Positional Operator:
$[<identifier>]
See the MongoDB server guide on Update Operators for a complete list.
Sample Documents
The examples in this guide use the following sample documents from the
test.pizza
collection. The collection contains documents that
describe the customers and their pizza orders as array elements in field
called items
.
[{ 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"], }, ], }]
Specifying Array Elements
You can specify which array elements to update using a positional operator. Positional operators can specify the first, all, or certain array elements to update.
To specify elements in an array with positional operators, use dot notation. Dot notation is a property access syntax for navigating BSON objects. To learn more, see dot notation.
The First Matching Array Element
To update the first array element of each document that matches your
query, use the positional operator $
.
The positional operator $
references the array matched by the query.
You cannot use this operator to reference a nested array. For cases in
which you want to access a nested array, use the
filtered positional operator.
Do not use the $
operator in an upsert
call because the
driver treats $
as a field name in the insert document.
Example
The following code snippet shows how 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);
The query 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 to set the
first array element match in items
to "extra large".
After you run the update method, your customer document for Steve Lobsters resembles the following:
{ name: "Steve Lobsters", address: "731 Yexington Avenue", items: [ { type: "pizza", size: "extra large", ... }, ... ] }
Note that we included both name
and items.type
fields in the query
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.
Matching All Array Elements
To perform the update on all of the array elements of each document that
matches your query, use the all positional operator $[]
.
Example
The following code snippet adds "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 resembles the following:
{ name:"Popeye", address: "1 Sweethaven", items: [ { type: "pizza", ... , toppings: ["garlic", "spinach", "fresh mozzarella"], }, { type: "calzone", ... , toppings: ["ham", "fresh mozzarella"], }, ] }
Matching Multiple Array Elements
To perform an update on all embedded array elements of each document
that matches your query, use the filtered positional operator
$[<identifier>]
.
The filtered positional operator $[<identifier>]
specifies the
matching array elements in the update document. To identify which array
elements to match, pair this operator with <identifier>
in an
options.arrayFilters
object.
The <identifier>
term is a placeholder value you assign that represents
an element of the array field name that prefixes it. This value must
start with a lowercase letter and contain only alphanumeric characters.
Example
To add a "garlic" topping to certain order items, format your update document as follows:
{ $push: { items.$[orderItem].toppings: "garlic" } }
This update document specifies the following:
$push
: the update operatoritems
: the array in the document to updateorderItem
: the identifier for the filtered positional operatortoppings
: the field on theitems
array element to updategarlic
: the value to push onto thetoppings
array
Next, add the matching criteria in your arrayFilters
object in your update
operation's options
parameter. This object is an array of queries
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:
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 you run the method, your customer document for Steve Lobsters resembles the following:
{ name: "Steve Lobsters", address: "731 Yexington Avenue", items: [ { type: "pizza", size: "large", toppings: ["pepperoni", "garlic"] }, { type: "pizza", size: "large", toppings: ["pineapple", "ham", "garlic"], ...}, ... ] }
Example
Suppose Steve Lobsters wants to adjust their order to add "salami" as a topping to all pizzas that have pepperoni. To perform the update, use the filtered positional operator 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 you run the update method, your customer document for Steve Lobsters 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", }, ], }