R
Rishtaara
MongoDB Fundamentals
Lesson 20 of 40Article15 min

Arithmetic Operators

MongoDB arithmetic operators ($add, $subtract, $multiply, $divide, and others) work inside aggregation pipeline stages — primarily $project and $addFields. They compute new fields from existing values at query time.

Arithmetic in aggregation expressions

MongoDB arithmetic operators ($add, $subtract, $multiply, $divide, and others) work inside aggregation pipeline stages — primarily $project and $addFields. They compute new fields from existing values at query time.

Real-life example: Arithmetic operators are like Excel formulas — you calculate tax, totals, and margins on the fly without storing every derived value.

  • $add — sum values (also concatenates strings if one operand is a string).
  • $subtract — difference of two values.
  • $multiply — product of values.
  • $divide — quotient (returns null if dividing by zero).
  • $mod — remainder after division.
  • $abs, $ceil, $floor, $round, $trunc — rounding and absolute value.

$add, $subtract, $multiply, $divide

These four operators cover most business calculations — line totals, tax, discounts, and averages. Pass an array of expressions; field references use $fieldName syntax.

Real-life example: Order total = sum of (price × qty) for each line item — $multiply per item, then $add to sum.

Basic arithmetic in $addFields
use rishtaara

// Add computed fields to products
db.products.aggregate([
  {
    $addFields: {
      taxAmount: { $multiply: ["$price", 0.18] },
      priceWithTax: {
        $add: ["$price", { $multiply: ["$price", 0.18] }]
      },
      discountedPrice: {
        $subtract: [
          "$price",
          { $multiply: ["$price", { $divide: ["$discountPercent", 100] }] }
        ]
      }
    }
  },
  { $match: { category: "electronics" } },
  { $project: { name: 1, price: 1, priceWithTax: 1, discountedPrice: 1 } }
])
Order line calculations
db.orders.aggregate([
  { $unwind: "$items" },
  {
    $addFields: {
      "items.lineTotal": {
        $multiply: ["$items.price", "$items.qty"]
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      orderNumber: { $first: "$orderNumber" },
      items: { $push: "$items" },
      subtotal: { $sum: { $multiply: ["$items.price", "$items.qty"] } }
    }
  },
  {
    $addFields: {
      tax: { $multiply: ["$subtotal", 0.18] },
      grandTotal: {
        $add: ["$subtotal", { $multiply: ["$subtotal", 0.18] }]
      }
    }
  }
])

$abs, $floor, $round, and related

Rounding operators clean up display values and bucket numeric data. $abs removes negative signs. $floor rounds down. $round accepts a place parameter.

Real-life example: $floor on a rating average is like truncating 4.7 stars to 4 for a simple display — no half-star graphics needed.

Rounding and absolute value
// Student score analysis
db.students.aggregate([
  {
    $project: {
      name: 1,
      grade: 1,
      scores: 1,
      avgScore: { $avg: "$scores.marks" },
      avgRounded: { $round: [{ $avg: "$scores.marks" }, 1] },
      avgFloored: { $floor: { $avg: "$scores.marks" } }
    }
  }
])

// Inventory adjustment — absolute value of stock change
db.inventory_logs.aggregate([
  {
    $project: {
      productName: 1,
      change: 1,
      absChange: { $abs: "$change" },
      direction: {
        $cond: {
          if: { $gte: ["$change", 0] },
          then: "restock",
          else: "sale"
        }
      }
    }
  }
])
Price bucketing with $floor and $divide
// Assign price tier: budget / mid / premium
db.products.aggregate([
  {
    $addFields: {
      priceTier: {
        $switch: {
          branches: [
            { case: { $lt: ["$price", 500] }, then: "budget" },
            { case: { $lt: ["$price", 2000] }, then: "mid" },
            { case: { $gte: ["$price", 2000] }, then: "premium" }
          ],
          default: "unknown"
        }
      },
      priceInThousands: {
        $divide: [{ $floor: "$price" }, 1000]
      }
    }
  },
  { $sort: { price: 1 } }
])

Examples in $project and $addFields

$project shapes output and can compute fields. $addFields adds new fields while keeping all existing ones. Choose $project when you want a slim response; $addFields when you need originals plus computed values.

Real-life example: $addFields is like adding a 'Total' column to a spreadsheet without hiding the original columns. $project is like exporting only selected columns.

Divide by zero returns null in MongoDB — handle with $cond or $ifNull in production pipelines. Store critical computed values at write time if reads are hot-path.
$project — computed report columns
// Product margin report
db.products.aggregate([
  {
    $project: {
      name: 1,
      category: 1,
      price: 1,
      cost: 1,
      margin: { $subtract: ["$price", "$cost"] },
      marginPercent: {
        $round: [
          {
            $multiply: [
              {
                $divide: [
                  { $subtract: ["$price", "$cost"] },
                  "$cost"
                ]
              },
              100
            ]
          },
          2
        ]
      },
      _id: 0
    }
  },
  { $match: { margin: { $gt: 0 } } },
  { $sort: { marginPercent: -1 } }
])
$addFields — enrich then filter
// Student age from birthYear (computed at query time)
db.students.aggregate([
  {
    $addFields: {
      age: { $subtract: [2024, "$birthYear"] },
      subjectCount: { $size: { $ifNull: ["$subjects", []] } },
      scoreGap: {
        $subtract: [100, { $ifNull: ["$scores.overall", 0] }]
      }
    }
  },
  {
    $match: {
      age: { $gte: 15 },
      "scores.overall": { $lt: 60 }
    }
  },
  {
    $project: {
      name: 1,
      grade: 1,
      age: 1,
      scoreGap: 1,
      needsSupport: {
        $cond: { if: { $gte: ["$scoreGap", 20] }, then: true, else: false }
      }
    }
  }
])