MongoDBElement Operators

Element Operators

Element operators query documents based on the presence or type of a field, rather than its value.

$exists — Field Presence

$exists checks whether a field exists in the document (regardless of its value, including null).

$exists examples

JS
// Find documents where the 'phone' field EXISTS (any value, even null)
db.users.find({ phone: { $exists: true } })

// Find documents where the 'phone' field does NOT EXIST
db.users.find({ phone: { $exists: false } })

// Find documents where the optional 'middleName' field is present
db.people.find({ middleName: { $exists: true } })

// Combine $exists with other operators
// Find documents where 'deletedAt' is present and is a date
db.posts.find({
  deletedAt: { $exists: true, $type: 'date' }
})
null vs Missing Fields

null vs missing

JS
// { field: null } matches BOTH documents with null value AND documents missing the field
db.users.find({ phone: null })
// Matches: { name: 'Alice', phone: null }      <- null value
// Matches: { name: 'Bob' }                     <- field is absent
// Does NOT match: { name: 'Carol', phone: '555-1234' }

// { field: { $eq: null } } — same behavior as above
db.users.find({ phone: { $eq: null } })

// To match ONLY documents where field EXISTS but is null:
db.users.find({ phone: { $exists: true, $eq: null } })
// Matches: { name: 'Alice', phone: null }      <- null value (yes)
// Does NOT match: { name: 'Bob' }              <- field is absent (no)

// To match ONLY documents where field is MISSING:
db.users.find({ phone: { $exists: false } })

Query

Matches null

Matches missing

{field: null}

Yes

Yes

{field: {$eq: null}}

Yes

Yes

{field: {$exists: false}}

No

Yes

{field: {$exists: true, $eq: null}}

Yes

No

$type — Field Type

$type selects documents where the field value is of the specified BSON type. You can use the type name string or numeric type code.

$type examples

JS
// Find documents where 'name' is stored as a string
db.users.find({ name: { $type: 'string' } })

// Find documents where 'age' is stored as a number (int or double)
db.users.find({ age: { $type: 'number' } })
// 'number' is an alias that matches double, int, long, and decimal

// Find documents where 'tags' is stored as an array
db.posts.find({ tags: { $type: 'array' } })

// Using numeric type codes (less readable but equivalent)
db.users.find({ name: { $type: 2 } })   // 2 = string
db.users.find({ age: { $type: 16 } })   // 16 = 32-bit int
BSON Type Aliases

Alias

BSON Type

Number

"double"

Double

1

"string"

String

2

"object"

Object

3

"array"

Array

4

"binData"

Binary

5

"bool"

Boolean

8

"date"

Date

9

"null"

Null

10

"int"

32-bit integer

16

"long"

64-bit integer

18

"decimal"

Decimal128

19

"objectId"

ObjectId

7

Using $type for Array Detection

Find array fields

JS
// Find documents where 'tags' is stored as an array
// Useful when the same field may be a string in some docs and an array in others
db.posts.find({ tags: { $type: 'array' } })

// Find documents where 'tags' is a plain string (not an array)
db.posts.find({ tags: { $type: 'string' } })

// Useful during migrations where schema was inconsistent:
// Some old docs: { tags: 'mongodb' }     <- string
// Some new docs: { tags: ['mongodb'] }   <- array
Checking for Mixed Types

$type with multiple types

JS
// Match documents where 'age' is stored as any numeric type
db.users.find({
  age: { $type: ['int', 'double', 'long'] }
})

// Match documents where a field is either a string or null
db.products.find({
  description: { $type: ['string', 'null'] }
})

// Numeric type codes also work in arrays
db.users.find({
  age: { $type: [16, 18, 1] }  // int32, int64, double
})
Practical Use: Data Cleanup Queries

Find incorrectly typed fields

JS
// Find documents where 'price' was accidentally stored as a string
// (should be a number)
db.products.find({ price: { $type: 'string' } })

// Find documents where 'createdAt' was stored as a string instead of Date
db.users.find({ createdAt: { $type: 'string' } })

// Find documents where 'isActive' is stored as a string instead of boolean
db.users.find({ isActive: { $type: 'string' } })

// Count how many documents have the wrong type (for impact assessment)
db.products.countDocuments({ price: { $type: 'string' } })

// Fix them: convert string prices to numbers
db.products.find({ price: { $type: 'string' } }).forEach(doc => {
  db.products.updateOne(
    { _id: doc._id },
    { $set: { price: parseFloat(doc.price) } }
  )
})
Tip
$exists: true combined with $type is a powerful way to validate that a field is both present AND the correct type — useful for data quality checks.
Note
The $type operator compares the stored BSON type, not the JavaScript type. MongoDB's BSON types are more granular than JavaScript types (e.g., int32 vs int64 vs double are all "number" in JS).