R
Rishtaara
MongoDB Fundamentals
Lesson 23 of 40Article20 min

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.

Push, capped history, and unique tags
// 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 from arrays
// 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.

Positional $ only updates the first match. If multiple array elements match, use $[] or arrayFilters (covered next).
Update first matching array element
// 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'.

$[] and arrayFilters
// 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" } }
)