Docs Menu
Docs Home
/ / /
Node.js Driver
/ / /

Update Arrays in a Document

On this page

  • Overview
  • Specifying Array Elements
  • The First Matching Array Element
  • Matching All Array Elements
  • Matching Multiple Array Elements

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>]

For a list of array update operators, see Update Operators in the Server Manual documentation.

Positional operators specify which array elements to update. You can use these operators to apply updates to the first element, all elements, or certain elements of an array that match a criteria.

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.

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. If you want to access a nested array, use the filtered positional operator.

Important

Do not use the $ operator in an upsert call because the driver treats $ as a field name in the insert document.

This example uses the following sample document to show how to update the first matching array element:

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

The following code shows how to increment a value in the first array element that matches a query.

The query matches elements in the entries array where the value of x is a string type. The update increases the y value by 33 in the first matching element.

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

After you run the update operation, the document resembles the following:

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

The example includes the entries.x field in the query to match the array that the $ operator applies an update to. If you omit the entries.x field from the query while using the $ operator in an update, the driver is unable to identify the matching array and raises the following error:

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

To perform the update on all array elements of each document that matches your query, use the all positional operator $[].

This example uses the following sample documents, which describe phone call logs, to show how to update all matching array elements:

{
_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 },
]
}

The following code shows how to remove the duration field from all calls array entries in the document whose date is "5/15/2023":

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

After you run the update operation, the documents resemble the following:

{
_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 },
]
}

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 arrayFilters object.

The <identifier> placeholder represents an element of the array field. You must select a value for <identifier> that starts with a lowercase letter and contains only alphanumeric characters.

You can use a filtered positional operator in an update operation. An update operation takes a query, an update document, and optionally, an options object as its parameters.

The following steps describe how to use a filtered positional operator in an update operation:

  1. Format your update document as follows:

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

    This update document contains the following placeholders:

    • $<operator>: The array update operator

    • <array>: The array in the document to update

    • <identifier>: The identifier for the filtered positional operator

    • <arrayField>: The field in the <array> array element to update

    • <updateParameter>: The value that describes the update

  2. Add the matching criteria in the arrayFilters object. This object is an array of queries that specify which array elements to include in the update. Set this object in an options parameter:

    arrayFilters: [
    { "<identifier>.<arrayField1>": <updateParameter1> },
    { "<identifier>.<arrayField2>": <updateParameter2> },
    ...
    ]
  3. Pass the query, the update document, and options to an update method. The following sample code shows how to call the updateOne() method with these parameters:

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

This example uses the following sample documents, which describe shopping lists for specific recipes, to show how to update certain matching array elements:

{
_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" }
]
}

Suppose you want to increase the quantity of items you purchase for a recipe on your "11/12/2023" grocery trip. You want to double the quantity if the item meets all the following criteria:

  • The item is for the "Fried rice" recipe.

  • The item name does not include the word "oil".

To double the quantity value in the matching array entries, use the filtered positional operator as shown in the following code:

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

The update multiplied the quantity value by 2 for items that matched the criteria. The item "Sesame oil" did not match the criteria in the arrayFilters object and therefore was excluded from the update. The following documents reflect these changes:

{
_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" }
]
}

Back

Modify Documents

Next

Insert or Update in a Single Operation