# mongo Async MongoDB wrapper over [motor](https://motor.readthedocs.io/). Thin, opinionated helpers for the common paths, with a raw escape hatch for everything else. ## Install `requirements.txt`: ``` mongo @ git+ssh://git@git.rethinkstudios.io/rethink-public/mongo.git@v0.1.4 ``` Direct: ```bash pip install "mongo @ git+ssh://git@git.rethinkstudios.io/rethink-public/mongo.git@v0.1.4" ``` Requires `motor` and `pymongo` (pulled transitively). Drop the `@v0.1.4` suffix from the line above to install the latest unpinned. ## Usage **Object (preferred)** — one client per process: ```python from mongo import MongoDB db = MongoDB(conn_string, database) # attach as bot.db / app.db await db.connect() # optional: ping to fail-early on a bad URI users = await db.get_documents("users", {"active": True}) db.close() # on shutdown (sync) # or with guaranteed cleanup: async with MongoDB(conn_string, database) as db: await db.get_documents("users", {"active": True}) ``` The class is `MongoDB`; **`Mongo` remains a back-compat alias** (`Mongo = MongoDB`), so existing `Mongo(...)` call sites keep working unchanged. **Module proxy (back-compat)** — arm once, then call bare: ```python import mongo # NOT `from mongo import ...` mongo.init(conn_string, database) users = await mongo.get_documents("users", {"active": True}) ``` Both styles share one client. The proxy exists so legacy call sites keep working after a one-line `init()`; new code should use the object. ## Naming consistency with the datastore trio mongo predates the `redis`/`psql`/`mysql` trio; this version makes it surface-consistent **without breaking anything** (all additive, every old name preserved): - class is **`MongoDB`** (with `Mongo` kept as an alias) - **`connect()`** + **`async with`** like the trio (motor connects lazily, so `connect()` just pings to validate early) - **`exists()`** aliases `check_document_exists()`; **`delete()`** aliases `delete_document()` — old names still work, the trio-consistent names are now available The one deliberate difference that remains: **mongo swallows** (see below) where the trio is **fail-loud**. That's intentional — flipping it would break existing consumers' branch- on-result control flow. ## Error contract - **Wrapped methods** log-and-swallow exceptions and return a safe default (`False` / `[]` / `{}` / `0` / `None`). Branch on the result. (`connect()` is the exception — it raises on a bad connection so you can fail-early.) - **`db.collection(name)`** (or `db[name]`) returns the raw motor collection: full driver surface, no swallowing, **raises**. Use it for anything not wrapped (`find_one_and_*` beyond what's exposed, change streams, complex bulk ops). ## API See the module docstring and method docstrings in `mongo.py` — that's the source of truth. Grouped as: collection/index management, create, read, update, delete, bulk, checks. Atomic ops (`find_one_and_update/replace/delete`) and `bulk_write` are included. ## Gotchas - `from mongo import func` won't see the proxy (resolved at import, before `init`). Use `import mongo` then `mongo.func(...)`. - `find_one_and_update` returns the **after** image by default (`return_after=True`). - `bulk_write` takes pymongo ops the caller builds: ```python from pymongo import UpdateOne ops = [UpdateOne({"_id": i}, {"$set": {...}}, upsert=True) for i in ids] await db.bulk_write("col", ops) ``` ## Versioning Releases are tagged `vX.Y.Z`. The install line above pins a release; drop the `@vX.Y.Z` suffix to install the latest unpinned. Pin deliberately for reproducible installs.