Usage Guide

This guide covers the core CRUD operations, document update patterns, and reference options supported by Mongomock's database and collection APIs.

Document Insertion & ID Management

When inserting documents, Mongomock automatically manages unique identifiers, BSON typing, and basic validation rules:

  • Automatic ID Assignment: If an insertion payload lacks an _id field, Mongomock generates and inserts a unique bson.objectid.ObjectId (or a simulated fallback) directly into the document copy.
  • Key Constraint Enforcement: Top-level document keys must be strings. Attempting to insert keys of other types (like integers or booleans) raises a ValueError or InvalidDocument exception.
  • No Duplicate IDs: Attempting to insert a document with an _id that already exists in the collection raises a DuplicateKeyError.
import mongomock

client = mongomock.MongoClient()
collection = client.ecommerce.products

# Success: Automatically appends an '_id'
item_id = collection.insert_one({"sku": "A-001", "price": 19.99}).inserted_id

# Raises DuplicateKeyError: Duplicate ID
try:
    collection.insert_one({"_id": item_id, "sku": "A-002"})
except mongomock.DuplicateKeyError as err:
    print(f"Insertion rejected: {err}")

Advanced Querying & Filtering

Mongomock supports MongoDB's query language, including subdocument filters, comparison operators, and array matching.

Subdocument Dot Notation

You can query nested values using dot-notation fields. Mongomock parses these dotted strings and traverses the document dictionary structure dynamically:

collection.insert_one({
    "sku": "M-404",
    "specs": {"dimensions": {"weight": 12, "unit": "kg"}}
})

# Query nested values
result = collection.find_one({"specs.dimensions.weight": {"$gt": 10}})
assert result["sku"] == "M-404"

Array Element Matching ($elemMatch)

Use $elemMatch to query documents containing array fields where at least one array element meets all specified filter criteria:

collection.insert_one({
    "sku": "P-200",
    "variants": [
        {"color": "red", "size": "S"},
        {"color": "blue", "size": "L"}
    ]
})

# Matches: One variant is both 'red' and 'S'
matching_item = collection.find_one({
    "variants": {"$elemMatch": {"color": "red", "size": "S"}}
})
assert matching_item is not None

Document Update Operators

You can modify existing documents using update_one or update_many. Updates support a wide range of atomic operators.

Field Modifications ($set, $unset, $inc, $max, $min)

# Increment stock and update description
collection.update_one(
    {"sku": "M-404"},
    {
        "$inc": {"stock": 5},
        "$set": {"status": "in-stock"},
        "$unset": {"discontinued": ""}
    }
)

Array Modifiers ($push, $pull, $pop)

You can modify arrays using positional indicators ($) and modifiers like $each, $slice, $position, and $sort:

# Seed an array
collection.insert_one({"_id": "arr_doc", "prices": [10, 20, 30]})

# Push multiple elements and trim the array to the last 4 items
collection.update_one(
    {"_id": "arr_doc"},
    {
        "$push": {
            "prices": {
                "$each": [40, 50, 60],
                "$slice": -4
            }
        }
    }
)

# Resulting array: [30, 40, 50, 60]
updated = collection.find_one({"_id": "arr_doc"})
assert updated["prices"] == [30, 40, 50, 60]

Atomic Find and Modify Operations

Mongomock supports atomic database transitions, allowing you to update a document and retrieve either its original or updated state using ReturnDocument:

from mongomock import ReturnDocument

# Increment a sequence and return the updated document state
sequence_doc = client.counters.ids.find_one_and_update(
    {"_id": "transaction_id"},
    {"$inc": {"seq": 1}},
    upsert=True,
    return_document=ReturnDocument.AFTER
)

print(f"Next transactional identifier: {sequence_doc['seq']}")

DBRefs & Reference Resolving

You can store logical relationships between collections using Database References (DBRef) and resolve them using Database.dereference():

from bson import DBRef

db = client.inventory_control

# 1. Insert product
laptop_id = db.products.insert_one({"model": "Latitude", "stock": 14}).inserted_id

# 2. Store DBRef in a separate collection
db.orders.insert_one({"order_no": 991, "product_ref": DBRef("products", laptop_id)})

# 3. Retrieve and resolve database reference
order_doc = db.orders.find_one({"order_no": 991})
product_doc = db.dereference(order_doc["product_ref"])

assert product_doc["model"] == "Latitude"
assert product_doc["stock"] == 14

To learn more about intercepting client connections and routing database calls, check out the Patching Guide.