R
Rishtaara
MongoDB Fundamentals
Lesson 22 of 40Article16 min

Array Expression Operators

Array expression operators work inside aggregation pipelines — in $project, $addFields, $group accumulators, and $match with $expr. They inspect and transform arrays without changing stored documents.

Array expressions in aggregation

Array expression operators work inside aggregation pipelines — in $project, $addFields, $group accumulators, and $match with $expr. They inspect and transform arrays without changing stored documents.

Real-life example: These operators are like a teacher counting how many subjects a student takes, reading the first subject on the list, or merging two class rosters — all in one report query.

  • $isArray — true if the value is an array
  • $size — number of elements (must know array size at query time)
  • $arrayElemAt — pick element by index (0-based)
  • $concatArrays — join two or more arrays
  • $reverseArray — reverse element order

$isArray and $size

$isArray returns a boolean — useful when documents might store a single value or an array depending on age of the schema.

$size returns the element count. It errors if the field is not an array — pair it with $isArray in conditional logic.

Real-life example: $size is counting items in a shopping cart before checkout — 'does this order have exactly 3 line items?'

$size in a find() filter requires an exact count — it cannot mean 'at least 3'. For that, use $expr with $gt and $size, or store itemCount denormalized.
Validate and count arrays in $project
db.orders.aggregate([
  {
    $project: {
      orderId: 1,
      itemCount: { $size: "$items" },
      tagsIsArray: { $isArray: "$tags" },
      hasManyItems: { $gt: [{ $size: "$items" }, 5] }
    }
  }
])

// Find orders with exactly 1 item (using $expr in find)
db.orders.find({
  $expr: { $eq: [{ $size: "$items" }, 1] }
})

$arrayElemAt — index into an array

$arrayElemAt takes an array and a zero-based index. Negative indices count from the end: −1 is the last element.

Real-life example: $arrayElemAt is grabbing the first name on a waitlist or the most recent entry in a log array.

First and last elements in a pipeline
db.students.aggregate([
  {
    $project: {
      name: 1,
      primarySubject: { $arrayElemAt: ["$subjects", 0] },
      latestGrade: { $arrayElemAt: ["$grades", -1] }
    }
  }
])

// Safe access when array might be empty — use $ifNull
db.students.aggregate([
  {
    $addFields: {
      topSubject: {
        $ifNull: [
          { $arrayElemAt: ["$subjects", 0] },
          "Undeclared"
        ]
      }
    }
  }
])

$concatArrays and $reverseArray

$concatArrays joins arrays in order — like stapling two lists together.

$reverseArray flips order — handy for 'newest first' display without sorting objects.

Real-life example: $concatArrays merges 'morning batch' and 'evening batch' student lists into one attendance sheet.

Merge tags and reverse activity feed
db.products.aggregate([
  {
    $project: {
      name: 1,
      allTags: {
        $concatArrays: [
          { $ifNull: ["$tags", []] },
          { $ifNull: ["$autoTags", []] }
        ]
      }
    }
  },
  {
    $project: {
      name: 1,
      allTags: 1,
      tagsNewestFirst: { $reverseArray: "$allTags" }
    }
  }
])

// Combine with $setUnion for unique tags (bonus)
db.products.aggregate([
  {
    $addFields: {
      uniqueTags: { $setUnion: ["$tags", "$autoTags"] }
    }
  }
])

Practical report: cart summary

Array expressions shine when embedded arrays hold line items, grades, or event history. Compute derived fields in the database instead of looping in Node.js.

Real-life example: A Rishtaara canteen app stores each student's weekly orders as an array — one aggregation returns total snacks bought without loading every document into the server.

Sum line items using array expressions
db.orders.aggregate([
  { $match: { status: "completed" } },
  {
    $addFields: {
      lineCount: { $size: "$items" },
      firstItemName: { $arrayElemAt: ["$items.name", 0] }
    }
  },
  {
    $group: {
      _id: "$userId",
      orderCount: { $sum: 1 },
      totalLines: { $sum: "$lineCount" }
    }
  },
  { $sort: { totalLines: -1 } },
  { $limit: 10 }
])