Skip to main content

MongoDB Bitwise Operators

Introduction​

Bitwise operators in MongoDB allow you to perform binary operations on integer values within your queries. These operators can be particularly useful for applications that store data in a bit-packed format or when you need to work with flags, permissions, or other bit-level operations.

MongoDB provides several bitwise operators that can help you query documents based on binary patterns or manipulate bit values. These operators can greatly simplify your code when dealing with binary data representations.

Why Use Bitwise Operators?​

Bitwise operations in MongoDB offer several advantages:

  1. Efficiency: Storing multiple boolean flags in a single integer field saves space
  2. Performance: Bitwise operations are typically faster than multiple field comparisons
  3. Simplicity: Complex permission systems can often be represented using bit flags

Available Bitwise Operators​

MongoDB provides the following bitwise operators:

OperatorDescription
$bitsAllClearMatches documents where all specified bit positions have a value of 0
$bitsAllSetMatches documents where all specified bit positions have a value of 1
$bitsAnyClearMatches documents where any of the specified bit positions has a value of 0
$bitsAnySetMatches documents where any of the specified bit positions has a value of 1

Let's explore each operator with examples.

Understanding Binary Data Representation​

Before diving into the operators, let's review how binary data works. In computing, data is stored in binary format (0s and 1s). For example, the decimal number 42 is represented in binary as 101010.

Binary positions have values based on powers of 2:

Position: 5   4   3   2   1   0
Value: 32 16 8 4 2 1
Binary: 1 0 1 0 1 0 = 42 in decimal

The $bitsAllClear Operator​

The $bitsAllClear operator matches documents where all specified bit positions have a value of 0 (are "clear").

Syntax​

javascript
{ <field>: { $bitsAllClear: <bitmask> } }

The <bitmask> can be:

  • A numeric bitmask
  • A binary string
  • An array of bit positions

Example 1: Using a numeric bitmask​

Let's say we have a collection of permission settings for users in our application:

javascript
db.permissions.insertMany([
{ user: "alice", permissionFlags: 20 }, // binary: 10100
{ user: "bob", permissionFlags: 15 }, // binary: 01111
{ user: "charlie", permissionFlags: 8 } // binary: 01000
])

To find users who don't have permission bits 1 and 3 set (both are 0):

javascript
db.permissions.find({ permissionFlags: { $bitsAllClear: 10 } }) // 10 in binary is 1010

This query will return:

javascript
{ "_id" : ObjectId("..."), "user" : "charlie", "permissionFlags" : 8 }

Charlie's permission value is 8 (01000 in binary). Both positions 1 and 3 contain 0, so it matches.

Example 2: Using an array of bit positions​

The same query can be written using bit positions:

javascript
db.permissions.find({ permissionFlags: { $bitsAllClear: [1, 3] } })

The $bitsAllSet Operator​

The $bitsAllSet operator matches documents where all specified bit positions have a value of 1 (are "set").

Syntax​

javascript
{ <field>: { $bitsAllSet: <bitmask> } }

Example: Finding users with specific permissions​

To find users who have both permission bits 0 and 2 set (both are 1):

javascript
db.permissions.find({ permissionFlags: { $bitsAllSet: 5 } }) // 5 in binary is 101

This query will return:

javascript
{ "_id" : ObjectId("..."), "user" : "bob", "permissionFlags" : 15 }

Bob's permission value is 15 (01111 in binary). Both positions 0 and 2 contain 1, so it matches.

The $bitsAnyClear Operator​

The $bitsAnyClear operator matches documents where any of the specified bit positions has a value of 0.

Syntax​

javascript
{ <field>: { $bitsAnyClear: <bitmask> } }

Example: Finding users missing at least one permission​

To find users who are missing at least one of the permissions at positions 0, 1, or 2:

javascript
db.permissions.find({ permissionFlags: { $bitsAnyClear: 7 } }) // 7 in binary is 111

This query will return:

javascript
{ "_id" : ObjectId("..."), "user" : "alice", "permissionFlags" : 20 }

Alice's permission value is 20 (10100 in binary). Position 1 is 0, so it matches.

The $bitsAnySet Operator​

The $bitsAnySet operator matches documents where any of the specified bit positions has a value of 1.

Syntax​

javascript
{ <field>: { $bitsAnySet: <bitmask> } }

Example: Finding users with at least one specific permission​

To find users who have at least one of the permissions at positions 2 or 4:

javascript
db.permissions.find({ permissionFlags: { $bitsAnySet: 20 } }) // 20 in binary is 10100

This query returns:

javascript
{ "_id" : ObjectId("..."), "user" : "alice", "permissionFlags" : 20 }
{ "_id" : ObjectId("..."), "user" : "bob", "permissionFlags" : 15 }
{ "_id" : ObjectId("..."), "user" : "charlie", "permissionFlags" : 8 }

All users have either bit 2 or 4 set, so all match.

Real-World Application: Permission System​

A common use case for bitwise operators is implementing a permission system. Each bit represents a specific permission:

Bit 0 (value 1): Read permission
Bit 1 (value 2): Write permission
Bit 2 (value 4): Delete permission
Bit 3 (value 8): Admin permission
Bit 4 (value 16): Super-admin permission

Let's create a users collection with permission flags:

javascript
db.users.insertMany([
{ name: "Regular User", permissions: 3 }, // Read + Write (1+2)
{ name: "Content Manager", permissions: 7 }, // Read + Write + Delete (1+2+4)
{ name: "Administrator", permissions: 15 }, // Read + Write + Delete + Admin (1+2+4+8)
{ name: "Super Admin", permissions: 31 } // All permissions (1+2+4+8+16)
])

Finding users with specific permission combinations​

  1. Users who can read but cannot delete:
javascript
db.users.find({ 
permissions: {
$bitsAllSet: 1, // Must have read permission
$bitsAllClear: 4 // Must not have delete permission
}
})
  1. Users who have admin-level access (admin or super-admin):
javascript
db.users.find({ permissions: { $bitsAnySet: 24 } }) // 24 is 16+8, looking for either bit
  1. Users who have all basic permissions but are not super-admin:
javascript
db.users.find({
permissions: {
$bitsAllSet: 15, // Has all basic permissions (1+2+4+8)
$bitsAllClear: 16 // Not super-admin
}
})

Performance Considerations​

When using bitwise operators:

  1. Indexing: Fields queried with bitwise operators can benefit from regular indexes, but specific bit patterns cannot be indexed directly.

  2. Readability: While bitwise operations are powerful, they can make code harder to understand for team members unfamiliar with binary operations.

  3. Field type: Bitwise operators only work on integer fields. Attempting to use them on non-integer fields will result in errors.

Summary​

MongoDB's bitwise operators provide a powerful way to work with binary data in your documents:

  • $bitsAllClear: All specified bits must be 0
  • $bitsAllSet: All specified bits must be 1
  • $bitsAnyClear: At least one of the specified bits must be 0
  • $bitsAnySet: At least one of the specified bits must be 1

These operators are particularly useful for permission systems, flags, and any scenario where you need to pack multiple boolean values into a single field.

Practice Exercises​

  1. Create a collection of devices with a status field where different bits represent different statuses (online, error, maintenance, etc.). Write queries to find:

    • All devices that are online but have an error
    • Devices in maintenance mode without errors
    • Any device that's either offline or in maintenance
  2. Implement a menu visibility system where each bit represents whether a menu item should be visible to a specific user role. Create queries to find:

    • Menu items visible to administrators but not regular users
    • Menu items visible to at least one user type
    • Menu items not visible to anyone (for debugging purposes)

Additional Resources​



If you spot any mistakes on this website, please let me know at feedback@compilenrun.com. I’d greatly appreciate your feedback! :)