100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
MongoDB

Working with Arrays and Nested Documents

Master querying and updating deeply nested MongoDB documents and arrays using dot notation, positional operators, and array update operators.

Schema DesignIntermediate9 min readJul 10, 2026
Analogies

Dot Notation for Nested Fields and Arrays

MongoDB lets you address nested fields and array elements using dot notation, both in queries and in update operators: address.city reaches into an embedded sub-document, and tags.0 reaches the first element of an array. For arrays of sub-documents, a query like { 'items.sku': 'ABC123' } matches any document where at least one array element has that sku, without needing to specify which index — this is the array's implicit $elemMatch-like behavior for a single-field condition. When you need multiple conditions to match on the *same* array element (not just each condition matching some element independently), you must use $elemMatch explicitly, otherwise MongoDB may match a document where condition A is satisfied by one element and condition B by a different element.

🏏

Cricket analogy: A scorecard query for 'any bowler with figures 5-for' matches the innings if any single bowler achieved it, but asking for 'a bowler with 5 wickets AND an economy under 3' needs both conditions checked on the same bowler's row, exactly like $elemMatch versus separate top-level conditions.

Updating Array Elements with Positional Operators

Updating a specific array element in place uses the positional $ operator, which stands in for the index of the first array element matched by the query filter — so db.orders.updateOne({ 'items.sku': 'ABC123' }, { $set: { 'items.$.qty': 5 } }) updates only the matched item's quantity. When you need to update *every* matching element rather than just the first, $[] updates all array elements unconditionally, and the filtered positional operator $[<identifier>] combined with arrayFilters updates every element that satisfies a specified sub-condition — for example, marking every item with qty below a threshold as lowStock: true in one call, across potentially many matching elements, without a client-side loop.

🏏

Cricket analogy: Updating just one fielder's position on a lineup card when the captain calls a specific change is like the $ positional operator, touching only the matched element, while resetting every fielder's position at a drinks break is like $[], touching all elements at once.

Array Update Operators: $push, $pull, $addToSet

Beyond modifying existing elements, MongoDB provides dedicated operators for adding and removing array elements atomically: $push appends one or more values (optionally with $each, $sort, and $slice modifiers to insert several items, keep the array sorted, and cap its size in a single operation), $pull removes all elements matching a condition, and $addToSet appends a value only if it isn't already present, giving you set-like uniqueness without a separate read-check-write round trip. Combining $push with $slice: -N is a common way to implement a bounded 'recent items' array directly at the database level — every push automatically trims the array back to the last N elements, which is a lightweight, race-condition-free alternative to application-level array trimming.

🏏

Cricket analogy: A team's 'recent form' tracker uses $push with $slice to append the latest match result and automatically drop anything beyond the last five games, keeping a bounded, always-current form guide without manual trimming.

javascript
// $elemMatch: both conditions must match the SAME array element
db.orders.find({
  items: { $elemMatch: { sku: "ABC123", qty: { $gte: 5 } } }
});

// Positional $ operator: update the first matched element in place
db.orders.updateOne(
  { _id: orderId, "items.sku": "ABC123" },
  { $set: { "items.$.qty": 5 } }
);

// arrayFilters: update every element matching a sub-condition
db.orders.updateOne(
  { _id: orderId },
  { $set: { "items.$[lowItem].lowStock": true } },
  { arrayFilters: [{ "lowItem.qty": { $lt: 3 } }] }
);

// $push + $slice: bounded 'recent activity' array capped at 10 entries
db.users.updateOne(
  { _id: userId },
  {
    $push: {
      recentActivity: {
        $each: [{ action: "login", ts: new Date() }],
        $slice: -10
      }
    }
  }
);

// $addToSet: append only if not already present
db.users.updateOne({ _id: userId }, { $addToSet: { interests: "mongodb" } });

$slice accepts a negative number to keep the last N elements or a positive number to keep the first N, applied after $each inserts the new elements and after $sort (if present) reorders the array — the order of evaluation is $each, then $sort, then $slice.

A common bug: querying with two separate top-level conditions on an array field (e.g., { 'items.sku': 'A', 'items.qty': { $gte: 5 } }) can match a document where sku 'A' has qty 2 and a different item has qty 10, because each condition is independently satisfied by some element. Use $elemMatch when the conditions must hold on the same element.

  • Dot notation ('a.b.c') addresses nested sub-document fields and array indices in queries and updates.
  • A single-field condition on an array field matches if any element satisfies it; multi-field conditions need $elemMatch to require the same element.
  • The positional $ operator updates the first array element matched by the query filter.
  • $[] updates every array element unconditionally; $[<id>] with arrayFilters updates every element matching a specified sub-condition.
  • $push (with $each, $sort, $slice) appends and can atomically bound array size; $pull removes matching elements; $addToSet enforces uniqueness on append.
  • $push combined with $slice is a lightweight, race-condition-free way to implement a bounded 'recent items' array server-side.
  • Array update operators are atomic at the single-document level, avoiding read-modify-write races in application code.

Practice what you learned

Was this page helpful?

Topics covered

#MongoDB#MongoDBStudyNotes#Database#WorkingWithArraysAndNestedDocuments#Arrays#Nested#Documents#Dot#DataStructures#StudyNotes#SkillVeris