R
Rishtaara
MongoDB Fundamentals
Lesson 24 of 40Article16 min

String Expression Operators

String expression operators format and compare text inside aggregation pipelines. They do not change stored documents unless you write results back with $merge or an update.

String operators in aggregation

String expression operators format and compare text inside aggregation pipelines. They do not change stored documents unless you write results back with $merge or an update.

Real-life example: These operators are like a mail-merge tool — combine first and last name, uppercase a coupon code, or compare two emails case-insensitively.

  • $concat — join strings
  • $toUpper / $toLower — change case
  • $strcasecmp — compare two strings (case-insensitive, returns −1/0/1)
  • $substrCP — slice by Unicode code points (safe for emoji and Devanagari)

$concat, $toUpper, and $toLower

$concat joins any number of strings and coerces non-strings where possible.

$toUpper and $toLower normalize case for display or matching.

Real-life example: $concat builds a display label 'Asha Kumar — Grade 10' from separate fields for a Rishtaara report card PDF.

Build display names and normalize codes
db.students.aggregate([
  {
    $project: {
      fullLabel: {
        $concat: ["$firstName", " ", "$lastName", " — Grade ", { $toString: "$grade" }]
      },
      emailLower: { $toLower: "$email" },
      couponNormalized: { $toUpper: "$couponCode" }
    }
  }
])

// Mask part of a phone for admin UI
db.users.aggregate([
  {
    $addFields: {
      phoneMasked: {
        $concat: [
          { $substrCP: ["$phone", 0, 2] },
          "****",
          { $substrCP: ["$phone", 6, 4] }
        ]
      }
    }
  }
])

$strcasecmp — compare without case

$strcasecmp returns 0 if strings are equal ignoring case, −1 if first is less, 1 if first is greater (lexicographic).

Prefer $strcasecmp over $toLower equality when sorting or branching in $cond.

Real-life example: $strcasecmp checks whether two signup emails are the same even if one user typed ASHA@Gmail.com.

Duplicate email detection in pipeline
db.signups.aggregate([
  {
    $addFields: {
      emailNormalized: { $toLower: "$email" }
    }
  },
  {
    $group: {
      _id: "$emailNormalized",
      count: { $sum: 1 },
      names: { $push: "$name" }
    }
  },
  { $match: { count: { $gt: 1 } } }
])

// Branch on string compare
db.products.aggregate([
  {
    $addFields: {
      tier: {
        $cond: {
          if: { $eq: [{ $strcasecmp: ["$category", "premium"] }, 0] },
          then: "A",
          else: "B"
        }
      }
    }
  }
])

$substrCP — safe substring

$substrCP(start, length) slices by Unicode code points — unlike legacy $substr which broke multi-byte characters.

Use it for initials, SKU prefixes, and fixed-width codes.

Real-life example: $substrCP takes the first two characters of a city name for a sort key — works for 'Mumbai' and emoji-rich social handles alike.

For full-text search in production, combine text indexes with $text or Atlas Search — string expressions are for formatting and light matching in pipelines.
Initials and SKU prefix reports
db.students.aggregate([
  {
    $project: {
      name: 1,
      initials: {
        $concat: [
          { $substrCP: ["$firstName", 0, 1] },
          ".",
          { $substrCP: ["$lastName", 0, 1] },
          "."
        ]
      },
      cityCode: { $substrCP: ["$address.city", 0, 3] }
    }
  }
])

// Group sales by SKU prefix (first 4 chars)
db.sales.aggregate([
  {
    $group: {
      _id: { $substrCP: ["$sku", 0, 4] },
      revenue: { $sum: "$amount" }
    }
  },
  { $sort: { revenue: -1 } }
])