Only show guides for your app
Connect Python to MongoDB with PyMongo — the panel's authSource connection string, one reusable client, and the full CRUD: insert_one, find, update_one with $inc, and delete_one.
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.
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.
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.
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:
dict — nested lists and dicts ("roles": ["member"]) are stored as-is, no separate table required. That flexibility is Mongo's whole appeal._id is 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 _id are fast.$inc (add to a number), $set (change a field), $push (append to an array) — change a document in place. $inc is atomic, exactly right for a balance or counter.upsert=True turns 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 in list(...) (or iterate it) to get the documents. Chain .sort(field, -1) for descending order and .limit(n) to cap it.💡 Tip:
flush=Trueon your
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.
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.
OperationFailure: Authentication failed — nearly always a missing or wrong authSource. 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' — add pymongo to requirements.txt (it installs on start) or install it from the Packages page, then restart.DuplicateKeyError (E11000) — a document with that _id already exists. Use update_one with upsert=True instead of another insert_one.Past connecting, this is standard driver territory — the official PyMongo documentation covers aggregation, transactions, and indexes.