MongoDB stores flexible, JSON-like documents instead of fixed rows — one of the three managed database types on Falix. From Python you reach it with PyMongo, the official driver. This guide connects to a database and runs the full set of create-read-update-delete operations, with the one connection-string detail that trips people up.
| At a glance | |
|---|---|
| You need | a MongoDB database (managed or your own server) and a Python app server |
| Plan | any |
| Time | about twenty-five minutes |
This is the Python companion to MongoDB from Node — same database, same operations. For the bigger picture of connecting any language, see Connect your app to a database.
Setup: the connection string (mind the authSource)
The panel gives you a MongoDB string shaped like this:
mongodb://user:pass@host:port/dbname?authSource=dbname
Copy it from the Databases page into your .env as DATABASE_URL (why not in code). Install the driver by adding pymongo to your requirements.txt — it installs automatically on the next start — or from the Packages page. On Falix the package is named pymongo.
🎯 Good to know: The
?authSource=dbnameon the end is required — it tells MongoDB which database holds your user account. On a managed Falix database that's your own database, soauthSourcematches the database name. Leave it off and you'll hit an authentication error even with the correct password. Use the panel's string exactly as given.
Connect once, reuse everywhere
MongoClient pools connections internally, so create it once when your app starts and reuse it — never one per request:
import os
from pymongo import MongoClient
client = MongoClient(os.environ["DATABASE_URL"])
db = client.get_default_database() # the database from the connection string
users = db["users"] # a collection is like a table
get_default_database() uses the database named in your connection string, so there's nothing to hard-code. A collection is Mongo's equivalent of a table — you don't define it or its columns first; it appears the moment you insert a document.
The full CRUD
Everything below was verified on Falix's Python 3.12 image against MongoDB 7:
# CREATE — insert one document
users.insert_one({"_id": "alice", "coins": 100, "roles": ["member"]})
# READ — find one by its id
print("READ:", users.find_one({"_id": "alice"}), flush=True)
# {'_id': 'alice', 'coins': 100, 'roles': ['member']}
# UPDATE — $inc adds to a number; upsert creates the doc if missing
users.update_one({"_id": "alice"}, {"$inc": {"coins": 25}})
users.update_one({"_id": "bob"}, {"$inc": {"coins": 10}}, upsert=True)
# READ MANY — filter, sort, collect into a list
print("ALL:", list(users.find({}).sort("coins", -1)), flush=True)
# [{'_id': 'alice', 'coins': 125, ...}, {'_id': 'bob', 'coins': 10}]
# DELETE — remove one
users.delete_one({"_id": "bob"})
print("COUNT:", users.count_documents({}), flush=True) # 1
client.close()
The parts worth knowing:
- A document is just a
dict— nested lists and dicts ("roles": ["member"]) are stored as-is, no separate table required. That flexibility is Mongo's whole appeal. _idis every document's unique, auto-indexed key. Set it yourself (a Discord user ID is a perfect_id) or let Mongo generate one, so lookups by_idare fast.- Update operators —
$inc(add to a number),$set(change a field),$push(append to an array) — change a document in place.$incis atomic, exactly right for a balance or counter. upsert=Trueturns an update into "update if it exists, else create it" — the first-seen-user convenience without a separate insert.find()returns a cursor; wrap it inlist(...)(or iterate it) to get the documents. Chain.sort(field, -1)for descending order and.limit(n)to cap it.
💡 Tip:
flush=Trueon your
No schema, but still design your shape
PyMongo won't enforce a schema, which is freeing until it isn't — some documents saying coins and others balance is a bug in waiting. Decide each document's shape up front and keep it consistent. The table-design shapes — one document per user, per guild, a separate collection for lists — apply to collections exactly as they do to SQL tables.
Verify it works
Start the server and watch the Console. The snippet prints the inserted document, then the sorted list after the updates (alice at 125 coins), then a final COUNT: 1. That output is the round trip confirmed: code to Mongo and back. Restart the app and query again — the documents persist, because a managed database outlives your server.
Troubleshooting
OperationFailure: Authentication failed— nearly always a missing or wrongauthSource. Use the panel's string verbatim, including?authSource=dbname; if you rotated the password, copy the fresh string into.env.ServerSelectionTimeoutError— wrong host/port or an unreachable database. Use the exact host from the database page; for your own Mongo server, use its public address and confirm it's running.ModuleNotFoundError: No module named 'pymongo'— addpymongotorequirements.txt(it installs on start) or install it from the Packages page, then restart.DuplicateKeyError(E11000) — a document with that_idalready exists. Useupdate_onewithupsert=Trueinstead of anotherinsert_one.
Past connecting, this is standard driver territory — the official PyMongo documentation covers aggregation, transactions, and indexes.