MongoDB $type Operator

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

What Is $type?

$type works with BSON types in two ways: as a query operator it filters documents by field type, and as an aggregation expression it returns the type name of a value (for example "string", "int", or "array").

Remember
$type = "what BSON type is this?"

Query (filter):
  { field: { $type: "string" } }

Expression (return name):
  { $type: "$field" }  → "string" | "int" | ...

"number" → any numeric type
["string","null"] → either type
missing field (expr) → "missing"
UsePrefer
Filter by BSON type$type in find / $match
Label each field’s type$type expression in $project
Numeric? true/false only$isNumber

How to Use $type in MongoDB

Pick query mode to filter, or expression mode to inspect and report types.

  1. Decide: filter documents (query) or return type names (aggregation).
  2. For queries, write { field: { $type: "string" } } in find() or $match.
  3. For pipelines, use { $type: "$field" } inside $addFields or $project.
  4. Use aliases like "number", or an array of types, when one exact type is too narrow.
PieceRequired?Role
Field / expressionYesValue whose type you care about
Type name / aliasQuery: yese.g. "string", "number", "array"
Expression formAgg: yesReturns the BSON type name string

Pseudocode

Pseudocode
// Query form
for each document:
    t = bsonType(document.field)
    if t is in allowedTypes:
        keep document

// Expression form
for each document:
    t = bsonType(evaluate(expression))
    emit { ..., valueType: t }   // e.g. "string"

Cheat Sheet

Keep these facts handy while checking BSON types.

TopicDetail
Query syntax{ field: { $type: "string" } }
Expression syntax{ $type: "$field" }
Common namesstring, int, double, array, object, null, bool, date, objectId
Alias"number" → int / long / double / decimal
Multi-type query{ $type: ["string", "null"] }
Missing (expr)returns "missing"
String vs number"88" is string; 88 is numeric

Live Preview

Watch expression-form $type name a value. Pick a sample and see its BSON-style type label.

Simulates expression $type (same idea as the mongosh examples below).

Result
value = 95

$type("$value") → "int"

{ valueType: "int" }

Worked Walkthrough — String vs Number

Two scores look similar: 95 (number) and "88" (string). Goal: keep only true strings with a query $type.

Calculation
Documents:
  { value: 95 }      // BSON type: int
  { value: "88" }    // BSON type: string

Query:
  { value: { $type: "string" } }

Check each:
  95   → type "int"    → reject
  "88" → type "string" → keep

Result:
  only the document with value "88"

MongoDB Examples

We use a small records collection with mixed types in value. First filter with a query, then inspect types in aggregation. Run these in mongosh after inserting the sample data once.

Example 1 — Sample Data

Imagine five records where value is sometimes a number, sometimes a string, and sometimes another BSON type. That mix is common in messy imports.

mongosh
db.records.insertMany([
  { _id: 1, label: "Score A", value: 95 },
  { _id: 2, label: "Score B", value: "88" },
  { _id: 3, label: "Tags", value: ["mongo", "db"] },
  { _id: 4, label: "Empty", value: null },
  { _id: 5, label: "Meta", value: { active: true } }
]);

How the Data Is Stored in MongoDB

After the insert, MongoDB keeps five documents in records. Run find() to see them:

mongosh
db.records.find()

Read the important fields like this:

FieldExampleBSON type
value95int
value"88"string
value["mongo", "db"]array
valuenullnull
value{ active: true }object

How It Works

  1. Insert once. insertMany adds five mixed-type documents to records.
  2. Types are stored as written. Quotes make "88" a string; bare 95 is numeric.
  3. find() shows the same shape. Ready for query and aggregation $type next.

Example 2 — Query by Type

Goal: keep only documents where value is a string. The numeric 95 must not match.

mongosh
db.records.find({
  value: { $type: "string" }
});

How It Works

  1. Read each value’s type. MongoDB checks the BSON type of value on every document.
  2. Match only strings. "88" is string; 95 is int, so it is skipped.
  3. Handy cleanup tip. Use { $type: "number" } when you want any numeric subtype instead.

Example 3 — Inspect Types

Same records, but use the aggregation expression form to add a valueType label for every document.

mongosh
db.records.aggregate([
  {
    $addFields: {
      valueType: { $type: "$value" }
    }
  }
]);

How It Works

  1. Same stored documents. Still using the five records from Example 1.
  2. Expression form returns a name. { $type: "$value" } becomes "int", "string", and so on.
  3. Great for audits. Add this field before a report or cleanup stage to spot unexpected types.
  4. Easy check. Score A should show valueType: "int"; Score B should show "string".

Edge Cases & Pitfalls

Check these before using $type in production queries and pipelines.

looks

Looks numeric ≠ is numeric

"88" is a string. Use "number" or convert with $convert / $toString as needed.

null

null is a type

Explicit null matches { $type: "null" }. A missing field is different and does not match that query filter.

forms

Query vs expression differ

Query form filters. Expression form returns a type name string. Do not mix the two shapes by accident.

alias

Prefer "number" for mixed numerics

Matching only "int" misses doubles. The "number" alias covers int, long, double, and decimal.

Performance Notes

ApproachCostBest for
Query $typeType check per docCleanup / schema filters
Expression $typePer-document labelAudits and reports
Filter earlyFewer later stagesPipelines that only need one type

Type checks are usually cheap. Put a query or $match $type early when later stages only handle one type.

Key Takeaways

  • Two forms: query filters by type; expression returns the type name.
  • Alias: "number" matches all numeric BSON types.
  • Quotes matter: "88" is string, not number.
  • Boolean check: prefer $isNumber when you only need yes/no for numbers.

One line: $type answers “what BSON type is this field?”—either as a filter or as a type-name label.

Frequently Asked Questions

$type works two ways. In find() or $match it filters documents where a field has a given BSON type. In aggregation expressions it returns the type name of a value, such as "string", "int", or "array".
Query form: { field: { $type: "string" } }. Expression form: { $type: "$field" }. You can also pass an array of types in queries, or use aliases like "number".
"number" matches any numeric BSON type: int, long, double, and decimal. Use it when you care that a field is numeric, not which numeric subtype.
$type returns (or filters by) BSON type names for any type. $isNumber is an aggregation expression that returns true or false for numeric values only.
In queries, a missing field does not match a $type filter. In aggregation expressions, $type on a missing field returns "missing".
Yes in queries. Pass an array such as { value: { $type: ["string", "null"] } } to match either type.

Next: $week

Return the week-of-year number from a date in an aggregation pipeline.

$week 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