MongoDB $filter Operator

Beginner
5 min read
Updated: Oct 2026
3 examples
Live preview

What Is $filter?

$filter is a MongoDB aggregation expression that returns a new array with only the elements that pass a condition. Order is preserved. Think of it like JavaScript array.filter() inside the pipeline.

Remember
$filter = keep matching array elements

{
  $filter: {
    input: <array>,
    as: "<name>",        // optional (default: this)
    cond: <boolean expr>,
    limit: <number>      // optional
  }
}

// reference current element with $$name
cond: { $gte: [ "$$item.price", 100 ] }

input null / missing → null
non-array input → error
output → new array (original order)
NeedPrefer
Keep some array items$filter
Transform each item$map
Collapse array to one value$reduce

How to Use $filter in MongoDB

Point at an array, name each element, write a boolean condition, then store the result in a stage.

  1. Choose an expression stage ($addFields or $project).
  2. Set input to the array field (for example "$items").
  3. Set as (for example "item") and write cond using "$$item".
  4. Optionally add limit to keep only the first N matches.
PieceRequired?Role
inputYesArray to scan
condYesBoolean keep/drop test
asNoName for each element (default this)
limitNoMax number of matches (≥ 1)

Pseudocode

Pseudocode
arr = evaluate(input)
if arr is null or missing:
    result = null
else:
    result = []
    for each element in arr (in order):
        if evaluate(cond) with $$as = element is true:
            append element to result
            if limit reached: stop
    emit { ..., field: result }

Cheat Sheet

Keep these facts handy while filtering embedded arrays.

TopicDetail
TypeAggregation expression (not a find filter)
Core syntax{ $filter: { input: "$items", as: "item", cond: ... } }
Element ref"$$item" / "$$item.price"
OrderSame as input array
Null inputReturns null
Related$map, $reduce, $gte
Sample checkprices ≥ 100 → keep those items

Live Preview

Watch $filter keep only items where price >= 100.

Simulates $filter with cond: { $gte: [ "$$item.price", 100 ] }.

Result
input:
  [ { name: "Pen", price: 80 }, { name: "Book", price: 120 },
    { name: "Mug", price: 45 }, { name: "Lamp", price: 200 } ]

cond: price >= 100

kept:
  [ { name: "Book", price: 120 }, { name: "Lamp", price: 200 } ]

Worked Walkthrough — Price ≥ 100

A cart has four items. We want only those with price >= 100.

Calculation
items:
  Pen  80   → 80  >= 100? false → drop
  Book 120  → 120 >= 100? true  → keep
  Mug  45   → 45  >= 100? false → drop
  Lamp 200  → 200 >= 100? true  → keep

$filter result (same order):
  [ Book 120, Lamp 200 ]

MongoDB Examples

We use one cart document with an items array. First we store it, then we keep expensive items, then we cap the result with limit. Run these in mongosh after inserting the sample data once.

Example 1 — Sample Data

Imagine one cart named Office with four line items and different prices.

mongosh
db.carts.insertOne({
  _id: 1,
  name: "Office",
  items: [
    { name: "Pen",  price: 80 },
    { name: "Book", price: 120 },
    { name: "Mug",  price: 45 },
    { name: "Lamp", price: 200 }
  ]
});

How the Data Is Stored in MongoDB

After the insert, MongoDB keeps one document in carts. Run find() to see it:

mongosh
db.carts.find()

Read that document like this:

Field in MongoDBValuePlain English
_id1Document id
name"Office"Cart label
itemsarray of 4 objectsEach object has name and price
Picture
items array:

  Pen 80 | Book 120 | Mug 45 | Lamp 200
              |
              v  $filter (price >= 100)
              |
         Book 120 | Lamp 200

How It Works

  1. Insert once. insertOne adds a single cart document to carts.
  2. Store an array. items holds embedded objects—exactly what $filter expects as input.
  3. find() shows the same shape. Ready for the filter examples next.

Example 2 — Filter by Price

Goal: keep only items where price >= 100.

mongosh
db.carts.aggregate([
  {
    $addFields: {
      expensive: {
        $filter: {
          input: "$items",
          as: "item",
          cond: { $gte: [ "$$item.price", 100 ] }
        }
      }
    }
  }
]);

How It Works

  1. Read the array. input: "$items" points at the stored cart lines.
  2. Name each element. as: "item" lets you use "$$item" in cond.
  3. Test the price. $gte keeps Book and Lamp; Pen and Mug are dropped.
  4. Add a new field. $addFields stores the result in expensive without deleting items.

Example 3 — Filter with Limit

Same condition, but keep only the first matching item (limit: 1).

mongosh
db.carts.aggregate([
  {
    $project: {
      name: 1,
      topExpensive: {
        $filter: {
          input: "$items",
          as: "item",
          cond: { $gte: [ "$$item.price", 100 ] },
          limit: 1
        }
      }
    }
  }
]);

How It Works

  1. Same condition. Still keep items with price >= 100.
  2. Stop early. limit: 1 returns only the first match in original order (Book before Lamp).
  3. Project a small shape. Output shows cart name and the limited array.
  4. Not a sort. Limit uses input order—it does not pick the highest price unless you sort first.

Edge Cases & Pitfalls

Check these before using $filter in production pipelines.

syntax

Use $$ for the element

Inside cond, write "$$item" (double dollar). A single "$item" looks for a document field named item.

null

Null input returns null

Missing or null arrays become null, not []. Guard with $ifNull if you need an empty array.

type

Input must be an array

A number or string in input errors the pipeline. Confirm the field is always an array.

limit

Limit is not “top N by value”

limit keeps the first N matches in input order. Sort the array first if you need the highest prices.

empty

No matches means []

When input is a valid array but nothing passes cond, $filter returns an empty array—not null.

Performance Notes

ApproachCostBest for
$filter on small arraysCheap per documentEmbedded lists (cart lines, tags)
$filter + limitCan stop earlyFirst few matches only
Huge nested arraysScans every elementConsider modeling / separate collection

$filter runs per document on that document’s array. Keep arrays reasonable in size, and filter documents with $match before heavy array work when you can.

Key Takeaways

  • Role: array → smaller array of matching elements.
  • Core pieces: input, cond, optional as / limit.
  • Element ref: "$$item" (double dollar).
  • Order: matches keep input order; limit is first N matches.

One line: $filter answers “which array items pass this test?”—and returns them in the same order.

Frequently Asked Questions

$filter returns a new array with only the elements from an input array that satisfy a condition. Matching items keep their original order. Use it inside aggregation stages such as $project and $addFields.
The syntax is { $filter: { input: <array>, as: <string>, cond: <expression> } }. Optionally add limit: <number> to cap how many matches are returned. as is optional and defaults to this.
Use the name from as with a double dollar prefix. If as is "item", reference the current element as "$$item" inside cond. Nested fields use "$$item.price".
$filter returns null when input is null or refers to a missing field. A non-array, non-null input causes an error.
No. $filter is an expression that builds a new array value for a stage like $addFields or $project. It does not update the collection unless you write results with a later stage such as $merge or $out.
Use limit when you only need the first N matches in original order. limit must be at least 1. If limit is larger than the number of matches, all matches are returned.

Next: $floor

Round a number down to the nearest integer in aggregation.

$floor tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

9 people found this page helpful