Works with the AI Agents you already use

    Claude CodeClaude CodeCursorCursorCodex CLICodex CLIMuseMuseDotsDots+22 more

    Beanie + MongoDB: Production Pitfalls

    1

    Catches the Beanie + MongoDB bugs that pass your tests and break production — with a pre-deploy index checker.

    $9.99

    Secure checkout via Stripe

    Money-back guarantee

    Converts to your local currency at checkout

    Security scanned
    Beanie + MongoDB: Production Pitfalls

    Beanie + MongoDB: Production Pitfalls

    Example session with this skill installed

    Refactor this to use Beanie's upsert API instead of the manual find/insert. It's called from webhook handlers.

    async def get_or_create_contact(org_id, email, name):
        contact = await Contact.find_one(Contact.organization_id == org_id, Contact.email == email)
        if contact is None:
            contact = Contact(organization_id=org_id, email=email, name=name, created_at=utcnow())
            await contact.insert()
        return contact
    
    • Read your context and instructions
    • Compiled the beanie + mongodb
    
    ## Summary
    Beanie's `.upsert(on_insert=...)` would keep the race, so the refactor uses one atomic server-side upsert backed by a unique index instead.
    
    ## Beanie's upsert API is not safe here
    In Beanie 2.1, `find_one(...).upsert(..., on_insert=Contact(...))` runs an `update_one` without `upsert=True` and, if nothing matched, a separate `insert_one`. That is the same check-then-insert race as the original code. Webhook providers redeliver events and deliver them concurrently, so this path would still produce duplicates or `DuplicateKeyError`.
    
    Instead the function uses the raw collection with `find_one_and_update(upsert=True)` and `$setOnInsert`: a single atomic operation that also returns the document in one round trip.
    
    ```python
    from datetime import UTC, datetime
    
    import pymongo
    from beanie import Document, PydanticObjectId
    from pymongo import ReturnDocument
    from pymongo.errors import DuplicateKeyError
    
    ```python
    class Contact(Document):
        organization_id: PydanticObjectId
        email: str
        name: str | None = None
        created_at: datetime
    
        class Settings:
            name = "contacts"
            indexes = [
    ```
    
                # The unique index is what makes the upsert atomic. Without it,
                # two concurrent upserts can both insert.
                pymongo.IndexModel(
                    [("organization_id", 1), ("email", 1)],
                    unique=True,
                    name="contacts_org_email_unique",
    
    ```
                ),
            ]
    ```
    
    async def get_or_create_contact(
        org_id: PydanticObjectId, email: str, name: str | None
    
    ```sql
    ) -> Contact:
        filter_ = {"organization_id": org_id, "email": email}
        update = {"$setOnInsert": {"name": name, "created_at": datetime.now(UTC)}}
        coll = Contact.get_pymongo_collection()
    
        for attempt in range(2):
            try:
                raw = await coll.find_one_and_update(
                    filter_,
                    update,
                    upsert=True,
                    return_document=ReturnDocument.AFTER,
                )
                break
            except DuplicateKeyError:
    ```
    
                # Lost a race on the unique index; the retry matches the winner's doc.
    
    ```
                if attempt:
                    raise
        return Contact.model_validate(raw)
    ```
    
    Requirements and behaviour
    
    ┌──────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
    │              │                                                                                                                                                                  │
    ├──────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ Unique index │ Required on (organization_id, email). Without it, two concurrent upserts can both insert.                                                                        │
    ├──────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ Retry        │ The loser of a race can still get DuplicateKeyError; it retries once and matches the winner's document. It never catches and logs, which would hide lost writes. │
    ├──────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ $setOnInsert │ name and created_at are written only on insert, so a repeat webhook doesn't overwrite an existing contact.                                                       │
    ├──────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ Timestamps   │ datetime.now(UTC) replaces utcnow(); the client must use tz_aware=True.                                                                                          │
    ├──────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ Tenant scope │ The filter includes organization_id.                                                                                                                             │
    └──────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
    
    Next steps
    
    - Before deploying: the old code has probably created duplicates already. Dedupe contacts and confirm zero violations against production, or building the new unique index crashes the boot. Run scripts/check_indexes.py against prod to verify.
    - Normalise emails (.strip().lower()) before calling, or different casings count as different contacts.
    - Add a test that fails against the old code: force the interleaving, or assert the index exists and that a second raw insert raises. mongomock doesn't model concurrency, so a plain asyncio.gather test proves nothing.
    

    Connects securely to your tools. The creator never sees your data.

    About this skill

    Your Beanie code passes review, the test suite is green, and the deploy rolls back. Or worse: it ships, and data quietly goes missing. This skill teaches your agent the failure modes that only show up in a real deployment, each one taken from a production incident in a multi-tenant SaaS running Beanie on MongoDB Atlas, and verified against the Beanie 2.1 source and a real MongoDB 8.0.

    What it prevents

    • Deploys that crash at boot. init_beanie builds indexes on startup. Change an index's keys under the same name, or add a unique index over existing duplicates, and every worker dies.
    • Fixes that never apply. Beanie never drops old indexes, so the stale constraint keeps enforcing after you "fixed" it.
    • Unique indexes on optional fields. Beanie writes null, sparse doesn't skip it, and the second document fails.
    • Race conditions. Check-then-insert, save() overwriting concurrent edits, and Beanie's own .upsert(on_insert=...), which is not atomic: it's an update followed by a separate insert.
    • Wrong totals. sort/skip/limit mutate the query and count() applies them, so pagination totals come back capped at the page size.
    • Green tests, red production. mongomock silently drops partialFilterExpression, raw aggregate() is a coroutine in prod but a cursor in tests, and asyncio.gather race tests pass against the buggy code.
    • Scripts that write when they should only read. A "dry-run" that calls init_beanie creates indexes in production, and a new TTL index starts deleting data within a minute. beanie migrate does the same.

    What you get

    • SKILL.md: 22 rules, each as symptom → cause → fix, plus a pre-deploy checklist for any model change.
    • Four reference guides with complete code: indexes, concurrency (atomic get-or-create, locks, sync jobs), testing (a mongomock fixture, race tests that actually fail), and operations (a safe script template, Atlas Search).
    • check_indexes.py: a read-only CLI that compares your models' indexes with a live database and tells you what the next deploy will do: boot blockers, duplicates that will break a unique index, documents a new TTL will delete, stale indexes still enforcing. Exits 1 on blockers, so it can gate CI.

    Measured, not claimed

    Six tasks built around these failure modes, no hints in the prompts, run with and without the skill:

    ModelWithout skillWith skill
    Claude Sonnet62%100%
    Claude Opus88%100%

    Without the skill, Sonnet used Beanie's non-atomic upsert for a webhook handler and disabled the real index in tests to keep CI green. Opus got most of them right, but only after reading Beanie's source or running experiments for up to two minutes per task.

    Works alongside MongoDB's official agent skills: they cover schema design and query tuning, this one covers how your Python code and your deploys behave.

    Demo: the requesttemplate, Atlas Search).

    • check_indexes.py: a read-only CLI that compares your models' indexes with a live database and tells you what the next deploy will do: boot blockers, duplicates that will break a unique index, documents a new TTL will delete, stale indexes still enforcing. Exits 1 on blockers, so it can gate CI.

    Measured, not claimed

    Six tasks built around these failure modes, no hints in the prompts, run with and without the skill:

    ModelWithout skillWith skill
    Claude Sonnet62%100%
    Claude Opus88%100%

    Without the skill, Sonnet used Beanie's non-atomic upsert for a webhook handler and disabled the real index in tests to keep CI green. Opus got most of them right, but only after reading Beanie's source or running experiments for up to two minutes per task.

    Works alongside MongoDB's official agent skills: they cover schema design and query tuning, this one covers how your Python code and your deploys behave.

    How to use

    Skills on Agensi run inside your AI agent. Copy the prompt, paste it into your agent, and it connects to Agensi and installs this skill for you. If a payment is needed, your agent shows it to you first.

    Reviews

    No reviews yet

    Be one of the first to try it. Every listed skill passes our trust checks below.

    Security scanned

    Passed our 8-point scan before listing

    Fresh listing

    Recently published to Agensi

    Money-back guarantee

    Doesn't do what its page promises? You get your money back.

    Trust & safety

    Security scanned

    Verified clean 14 days ago

    • Passed all security checks, Safe to install

    Listed14 days ago

    What's inside

    Frequently Asked Questions