Array Update Operators
Documents often store lists — tags, cart items, grades, permissions. Array update operators modify those lists without replacing the whole document.
Updating arrays in place
Documents often store lists — tags, cart items, grades, permissions. Array update operators modify those lists without replacing the whole document.
Real-life example: Array updates are like editing a guest list — add a name, remove someone who cancelled, or change one person's seat without reprinting the whole list.
- $push — append values to an array
- $addToSet — append only if not already present
- $pull — remove all matching values
- $pullAll — remove listed values
- $pop — remove first or last element
- Positional $ and $[] — update matched array elements
$push and $addToSet
$push adds one or more elements to an array. Use $each to push many at once, $sort to order, and $slice to cap length (useful for 'last 50 messages').
$addToSet only inserts if the value is not already in the array — ideal for tags and unique IDs.
Real-life example: $push is adding a book to a library checkout list. $addToSet is adding a hashtag — duplicates are ignored.
// Add a subject to a student
db.students.updateOne(
{ email: "rahul@rishtaara.edu" },
{ $push: { subjects: "Economics" } }
)
// Push multiple + keep only last 20 log entries
db.users.updateOne(
{ _id: userId },
{
$push: {
activityLog: {
$each: [{ action: "login", at: new Date() }],
$sort: { at: -1 },
$slice: 20
}
}
}
)
// Tag without duplicates
db.products.updateOne(
{ sku: "MOUSE-01" },
{ $addToSet: { tags: { $each: ["wireless", "bestseller", "wireless"] } } }
)$pull, $pullAll, and $pop
$pull removes every array element that matches a condition (or exact value).
$pullAll removes all occurrences of listed values.
$pop removes one end: −1 removes the last element, 1 removes the first.
Real-life example: $pull is striking cancelled items off an order. $pop is removing the most recently added item from a stack.
// Remove "clearance" tag everywhere it appears
db.products.updateOne(
{ sku: "MOUSE-01" },
{ $pull: { tags: "clearance" } }
)
// Pull objects matching a condition
db.orders.updateOne(
{ _id: orderId },
{ $pull: { items: { qty: 0 } } }
)
// Remove several status flags at once
db.tasks.updateMany(
{},
{ $pullAll: { flags: ["draft", "archived"] } }
)
// Remove last chat message
db.rooms.updateOne(
{ roomId: "general" },
{ $pop: { messages: 1 } }
)Positional $ — update one matched element
When your filter matches a document and an array element, the positional $ operator updates the first matching array element.
The filter must include the array field so MongoDB knows which element matched — e.g. { 'items.sku': 'ABC' } with { $set: { 'items.$.qty': 3 } }.
Real-life example: Positional $ is updating one student's grade in a class roster when you know their roll number — not everyone's grade.
// Bump quantity for one line item in a cart
db.carts.updateOne(
{ userId: userId, "items.sku": "NOTEBOOK-A5" },
{
$inc: { "items.$.qty": 1 },
$set: { "items.$.updatedAt": new Date() }
}
)
// Mark one notification as read
db.users.updateOne(
{ _id: userId, "notifications.id": notifId },
{ $set: { "notifications.$.read": true } }
)All positional $[] and arrayFilters
$[] updates every element in an array when the filter matches the document — no per-element filter in the query.
arrayFilters (update option) gives named placeholders like $[elem] for fine-grained multi-element updates.
Real-life example: $[] is marking every item in a shipment as 'in transit'. arrayFilters is updating only items where status is 'pending'.
// Discount every line item in matching orders
db.orders.updateMany(
{ status: "open" },
{ $mul: { "items.$[].price": 0.9 } }
)
// Only update items that are still pending
db.orders.updateMany(
{ _id: orderId },
{ $set: { "items.$[line].status": "shipped" } },
{ arrayFilters: [{ "line.status": "pending" }] }
)
// $elemMatch in query + positional $ for nested match
db.students.updateOne(
{
name: "Asha",
grades: { $elemMatch: { subject: "Math", score: { $lt: 40 } } }
},
{ $set: { "grades.$.remark": "Remedial class required" } }
)