Mango DBLesson 13 – Query Filters | Dataplexa

Query Filters

A query filter is the object you pass to find(), find_one(), update_one(), delete_one(), and almost every other MongoDB operation to specify which documents to match. Filters are written as plain Python dictionaries — no string parsing, no SQL injection risk. MongoDB provides a rich set of operators that cover every matching scenario: comparisons, logical combinations, element checks, array queries, and regular expressions. Mastering filters means you can pinpoint exactly the documents you need in any collection.

Every example in this lesson runs against the Dataplexa Store dataset.

Exact Match — The Simplest Filter

The most basic filter is an exact match — specify a field name and the value it must equal. MongoDB checks every document in the collection (or index, if one exists) and returns those where the field equals the value exactly.

# Exact match filters — field must equal the specified value

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")
db     = client["dataplexa"]

# Single field exact match
premium_users = db.users.find({"membership": "premium"})
print("Premium users:")
for u in premium_users:
    print(f"  {u['name']} ({u['country']})")

# Multi-field exact match — ALL conditions must be true (implicit AND)
uk_premium = db.users.find({"membership": "premium", "country": "UK"})
print("\nPremium users in UK:")
for u in uk_premium:
    print(f"  {u['name']}")

# Exact match on a nested field using dot notation
london_users = db.users.find({"city": "London"})
print("\nUsers in London:")
for u in london_users:
    print(f"  {u['name']}")
Premium users:
Alice Johnson (UK)
Clara Diaz (Spain)
Eva Müller (Germany)

Premium users in UK:
Alice Johnson

Users in London:
Alice Johnson
  • Multiple fields in one filter are combined with an implicit AND — all conditions must be satisfied
  • Exact match is case-sensitive — "Premium" does not match "premium"
  • Exact match on an array field matches documents where the array contains that value — e.g. {"tags": "newsletter"} matches any user whose tags array includes "newsletter"

Comparison Operators

Comparison operators let you match documents where a field is greater than, less than, or not equal to a value. They are the backbone of range queries — finding products within a price band, orders above a total, or users above a certain age.

# Comparison operators — $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")
db     = client["dataplexa"]

# $gt — products with price greater than $50
expensive = db.products.find(
    {"price": {"$gt": 50}},
    {"name": 1, "price": 1, "_id": 0}
)
print("Products over $50:")
for p in expensive:
    print(f"  ${p['price']:>7.2f}  {p['name']}")

# $gte / $lte — products in the $20–$100 range
mid_range = db.products.find(
    {"price": {"$gte": 20, "$lte": 100}},
    {"name": 1, "price": 1, "_id": 0}
)
print("\nProducts $20–$100:")
for p in mid_range:
    print(f"  ${p['price']:>7.2f}  {p['name']}")

# $ne — all orders that are NOT delivered
not_delivered = db.orders.find(
    {"status": {"$ne": "delivered"}},
    {"_id": 1, "status": 1}
)
print("\nOrders not delivered:")
for o in not_delivered:
    print(f"  {o['_id']} — {o['status']}")

# $in — users from UK or Germany
uk_de = db.users.find(
    {"country": {"$in": ["UK", "Germany"]}},
    {"name": 1, "country": 1, "_id": 0}
)
print("\nUsers from UK or Germany:")
for u in uk_de:
    print(f"  {u['name']} ({u['country']})")

# $nin — products NOT in Electronics
non_electronic = db.products.find(
    {"category": {"$nin": ["Electronics"]}},
    {"name": 1, "category": 1, "_id": 0}
)
print("\nNon-electronics products:")
for p in non_electronic:
    print(f"  {p['name']} ({p['category']})")
Products over $50:
$ 89.99 Mechanical Keyboard
$299.99 Monitor 27-inch
$349.99 Standing Desk

Products $20–$100:
$ 29.99 Wireless Mouse
$ 49.99 USB-C Hub
$ 89.99 Mechanical Keyboard

Orders not delivered:
o002 — shipped
o004 — processing
o006 — cancelled

Users from UK or Germany:
Alice Johnson (UK)
Bob Smith (UK)
Eva Müller (Germany)

Non-electronics products:
Notebook A5 (Stationery)
Standing Desk (Furniture)
Ballpoint Pens 10-pack (Stationery)
  • $in accepts a list of values — the field must equal any one of them. It is more efficient than multiple $or conditions on the same field
  • $nin is the inverse of $in — matches documents where the field does not equal any value in the list
  • Combine $gte and $lte on the same field for a range query — both operators apply to the same field simultaneously

Logical Operators

Logical operators combine multiple filter conditions. $and requires all conditions to be true, $or requires at least one to be true, $not inverts a condition, and $nor requires all conditions to be false.

# Logical operators — $and, $or, $not, $nor

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")
db     = client["dataplexa"]

# $or — products that are either in Furniture OR cost less than $5
budget_or_furniture = db.products.find(
    {"$or": [
        {"category": "Furniture"},
        {"price": {"$lt": 5}}
    ]},
    {"name": 1, "category": 1, "price": 1, "_id": 0}
)
print("Furniture OR under $5:")
for p in budget_or_furniture:
    print(f"  {p['name']:30} ${p['price']:>7.2f}  ({p['category']})")

# $and — explicit AND (useful when filtering on the same field twice)
# Find products in Electronics with a rating above 4.4
top_electronics = db.products.find(
    {"$and": [
        {"category": "Electronics"},
        {"rating": {"$gt": 4.4}}
    ]},
    {"name": 1, "rating": 1, "_id": 0}
)
print("\nTop-rated Electronics (rating > 4.4):")
for p in top_electronics:
    print(f"  {p['name']} — rating: {p['rating']}")

# $nor — orders that are neither cancelled NOR processing
active = db.orders.find(
    {"$nor": [
        {"status": "cancelled"},
        {"status": "processing"}
    ]},
    {"_id": 1, "status": 1}
)
print("\nOrders not cancelled and not processing:")
for o in active:
    print(f"  {o['_id']} — {o['status']}")

# $not — users who are NOT basic members
not_basic = db.users.find(
    {"membership": {"$not": {"$eq": "basic"}}},
    {"name": 1, "membership": 1, "_id": 0}
)
print("\nNon-basic members:")
for u in not_basic:
    print(f"  {u['name']} — {u['membership']}")
Furniture OR under $5:
Standing Desk $349.99 (Furniture)
Notebook A5 $ 4.99 (Stationery)
Ballpoint Pens 10-pack $ 3.49 (Stationery)

Top-rated Electronics (rating > 4.4):
Wireless Mouse — rating: 4.5
Mechanical Keyboard — rating: 4.7
Monitor 27-inch — rating: 4.6

Orders not cancelled and not processing:
o001 — delivered
o002 — shipped
o003 — delivered
o005 — delivered
o007 — delivered

Non-basic members:
Alice Johnson — premium
Clara Diaz — premium
Eva Müller — premium
  • Multi-field implicit AND (comma-separated in one dict) is more concise than explicit $and for different fields
  • Use explicit $and when you need two conditions on the same field — a single dict key can only appear once
  • $not wraps another operator — it cannot be used alone at the top level without an operator inside it

Element Operators

Element operators check whether a field exists in a document or what type it is — essential for working with flexible schemas where different documents may have different fields.

# Element operators — $exists, $type

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")
db     = client["dataplexa"]

# $exists — find users who have a tags field
has_tags = db.users.find(
    {"tags": {"$exists": True}},
    {"name": 1, "tags": 1, "_id": 0}
)
print("Users with a tags field:")
for u in has_tags:
    print(f"  {u['name']} — tags: {u['tags']}")

# $exists: False — find documents missing a field
no_phone = db.users.find(
    {"phone": {"$exists": False}},
    {"name": 1, "_id": 0}
)
print("\nUsers with no phone field:")
for u in no_phone:
    print(f"  {u['name']}")

# $type — find products where price is a double (correctly typed)
numeric_prices = db.products.find(
    {"price": {"$type": "double"}},
    {"name": 1, "price": 1, "_id": 0}
)
print("\nProducts with numeric (double) price:")
for p in numeric_prices:
    print(f"  {p['name']} — ${p['price']}")
Users with a tags field:
Alice Johnson — tags: ['early_adopter', 'newsletter']
Bob Smith — tags: ['newsletter']
Clara Diaz — tags: ['early_adopter']
David Lee — tags: []
Eva Müller — tags: ['early_adopter', 'newsletter']

Users with no phone field:
Alice Johnson
Bob Smith
Clara Diaz
David Lee
Eva Müller

Products with numeric (double) price:
Wireless Mouse — $29.99
Mechanical Keyboard — $89.99
Notebook A5 — $4.99
Standing Desk — $349.99
USB-C Hub — $49.99
Ballpoint Pens 10-pack — $3.49
Monitor 27-inch — $299.99
  • $exists: True matches documents that have the field — even if its value is null
  • $exists: False is invaluable during data quality audits — finding documents that are missing required fields
  • Combine $exists and $type during schema migrations to identify and fix incorrectly typed fields

Array Filters

MongoDB makes querying arrays natural — you can match on a single element, require multiple elements to be present, or use $elemMatch to apply multiple conditions to the same array element.

# Array filter operators — $all, $size, $elemMatch

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")
db     = client["dataplexa"]

# Simple array element match — find users tagged 'newsletter'
newsletter = db.users.find(
    {"tags": "newsletter"},
    {"name": 1, "tags": 1, "_id": 0}
)
print("Users tagged 'newsletter':")
for u in newsletter:
    print(f"  {u['name']} — {u['tags']}")

# $all — users who have BOTH tags
both_tags = db.users.find(
    {"tags": {"$all": ["early_adopter", "newsletter"]}},
    {"name": 1, "tags": 1, "_id": 0}
)
print("\nUsers with both 'early_adopter' AND 'newsletter' tags:")
for u in both_tags:
    print(f"  {u['name']}")

# $size — users with exactly 2 tags
two_tags = db.users.find(
    {"tags": {"$size": 2}},
    {"name": 1, "tags": 1, "_id": 0}
)
print("\nUsers with exactly 2 tags:")
for u in two_tags:
    print(f"  {u['name']} — {u['tags']}")

# $elemMatch — orders containing an item from product p001 with qty > 0
has_p001 = db.orders.find(
    {"items": {"$elemMatch": {"product_id": "p001", "qty": {"$gte": 1}}}},
    {"_id": 1, "user_id": 1, "total": 1}
)
print("\nOrders containing product p001:")
for o in has_p001:
    print(f"  {o['_id']} — user: {o['user_id']}  total: ${o['total']}")
Users tagged 'newsletter':
Bob Smith — ['newsletter']
Alice Johnson — ['early_adopter', 'newsletter']
Eva Müller — ['early_adopter', 'newsletter']

Users with both 'early_adopter' AND 'newsletter' tags:
Alice Johnson
Eva Müller

Users with exactly 2 tags:
Alice Johnson — ['early_adopter', 'newsletter']
Eva Müller — ['early_adopter', 'newsletter']

Orders containing product p001:
o001 — user: u001 total: $44.96
o005 — user: u004 total: $329.98
  • A plain array equality check ({"tags": "newsletter"}) matches any document where the array contains that value
  • $all requires every listed value to be present in the array — order does not matter
  • $elemMatch is essential when you need multiple conditions to apply to the same array element — without it, conditions could match different elements
  • $size matches arrays of an exact length — it cannot be combined with range operators like $gt

Regular Expression Filters

The $regex operator matches string fields against a regular expression — useful for partial string matching, case-insensitive search, and pattern validation.

# $regex — pattern matching on string fields

from pymongo import MongoClient

client = MongoClient("mongodb://localhost:27017/")
db     = client["dataplexa"]

# Find products whose name starts with "Wire" or "Mech"
starts_w = db.products.find(
    {"name": {"$regex": "^Wire", "$options": "i"}},
    {"name": 1, "_id": 0}
)
print("Products starting with 'Wire':")
for p in starts_w:
    print(f"  {p['name']}")

# Case-insensitive search — products containing "board" anywhere
contains_board = db.products.find(
    {"name": {"$regex": "board", "$options": "i"}},
    {"name": 1, "_id": 0}
)
print("\nProducts containing 'board' (case-insensitive):")
for p in contains_board:
    print(f"  {p['name']}")

# Find users whose email ends with @example.com
example_emails = db.users.find(
    {"email": {"$regex": "@example\\.com$"}},
    {"name": 1, "email": 1, "_id": 0}
)
print("\nUsers with @example.com email:")
for u in example_emails:
    print(f"  {u['name']} — {u['email']}")
Products starting with 'Wire':
Wireless Mouse

Products containing 'board' (case-insensitive):
Mechanical Keyboard

Users with @example.com email:
Alice Johnson — alice@example.com
Bob Smith — bob@example.com
Clara Diaz — clara@example.com
David Lee — david@example.com
Eva Müller — eva@example.com
  • $options: "i" makes the match case-insensitive — use it for user-facing search
  • ^ anchors the pattern to the start of the string, $ anchors to the end
  • Regex filters cannot use standard indexes efficiently unless the pattern is anchored to the start (^prefix) — for full-text search on large collections use a text index or Atlas Search instead

Summary Table

Operator Category Matches When Example
$eq Comparison Field equals value {"age": {"$eq": 30}}
$gt / $gte Comparison Field greater than / or equal {"price": {"$gte": 50}}
$in Comparison Field equals any value in list {"country": {"$in": ["UK","DE"]}}
$or Logical At least one condition is true {"$or": [{...},{...}]}
$exists Element Field exists / does not exist {"phone": {"$exists": false}}
$all Array Array contains all listed values {"tags": {"$all": ["a","b"]}}
$elemMatch Array One array element matches all conditions {"items": {"$elemMatch": {...}}}
$regex Evaluation String matches a pattern {"name": {"$regex": "^Wire"}}

Practice Questions

Practice 1. Write a filter to find all products in the Dataplexa Store with a price between $10 and $100 inclusive.



Practice 2. What is the difference between using $or and listing multiple fields in a single filter dict?



Practice 3. Why is $elemMatch necessary when filtering on multiple conditions inside an array of sub-documents?



Practice 4. Write a filter to find all users in the Dataplexa Store from either Spain or USA.



Practice 5. What $regex option makes a pattern match case-insensitively?



Quiz

Quiz 1. Which operator would you use to find products whose category is one of three possible values?






Quiz 2. What does {"tags": "early_adopter"} match in MongoDB?






Quiz 3. When must you use explicit $and instead of the implicit multi-field AND?






Quiz 4. What does $exists: false match?






Quiz 5. Which regex anchor ensures a pattern only matches at the beginning of a string?






Next up — Projection: controlling exactly which fields MongoDB returns to keep responses lean and secure.