Monty, Mongo tinified. MongoDB implemented in Python!
Inspired by TinyDB and it's extension TinyMongo
A pure Python-implemented database that looks and works like MongoDB.
>>> from montydb import MontyClient
>>> col = MontyClient(":memory:").db.test
>>> col.insert_many( [{"stock": "A", "qty": 6}, {"stock": "A", "qty": 2}] )
>>> cur = col.find( {"stock": "A", "qty": {"$gt": 4}} )
>>> next(cur)
{'_id': ObjectId('5ad34e537e8dd45d9c61a456'), 'stock': 'A', 'qty': 6}Most of the CRUD operators have been implemented. You can visit issue #14 to see the full list.
This project is tested against:
- MongoDB: 3.6, 4.0, 4.2 (4.4 on the wayπ¦)
- Python: 3.7, 3.8, 3.9, 3.10, 3.11, 3.12
pip install montydbOr with uv:
uv pip install montydb-
optional, to use real
bsonin operation (pymongowill be installed) For minimum requirements,montydbships with it's own fork ofObjectIdinmontydb.types, so you may ignore this option ifObjectIdis all you need frombsonpip install montydb[bson]
uv pip install montydb[bson]
-
optional, to use lightning memory-mapped db as storage engine
pip install montydb[lmdb]
uv pip install montydb[lmdb]
π¦ Available storage engines:
- in-memory
- flat-file
- sqlite
- lmdb (lightning memory-mapped db)
Depending on which one you use, you may have to configure the storage engine before you start.
β οΈ The configuration process only required on repository creation or modification. And, one repository (the parent level of databases) can only assign one storage engine.
To configure a storage, see flat-file storage for example:
from montydb import set_storage, MontyClient
set_storage(
# general settings
repository="/db/repo", # dir path for database to live on disk, default is {cwd}
storage="flatfile", # storage name, default "flatfile"
mongo_version="4.0", # try matching behavior with this mongodb version
use_bson=False, # default None, and will import pymongo's bson if None or True
# any other kwargs are storage engine settings.
cache_modified=10, # the only setting that flat-file have
)
# ready to goOnce that done, there should be a file named monty.storage.cfg saved in your db repository path. It would be /db/repo for the above examples.
Now let's moving on to each storage engine's config settings.
memory storage does not need nor have any configuration, nothing saved to disk.
from montydb import MontyClient
client = MontyClient(":memory:")
# ready to goflatfile is the default on-disk storage engine.
from montydb import set_storage, MontyClient
set_storage("/db/repo", cache_modified=5) # optional step
client = MontyClient("/db/repo") # use current working dir if no path given
# ready to goFlatFile config:
[flatfile]
cache_modified: 0 # how many document CRUD cached before flush to disk.sqlite is NOT the default on-disk storage, need configuration first before getting client.
Pre-existing sqlite storage file which saved by
montydb<=1.3.0is not read/writeable aftermontydb==2.0.0.
from montydb import set_storage, MontyClient
set_storage("/db/repo", storage="sqlite") # required, to set sqlite as engine
client = MontyClient("/db/repo")
# ready to goSQLite config:
[sqlite]
journal_mode = WAL
check_same_thread = # Leave it empty as False, or any value will be TrueOr,
repo = "path_to/repo"
set_storage(
repository=repo,
storage="sqlite",
use_bson=True,
# sqlite pragma
journal_mode="WAL",
# sqlite connection option
check_same_thread=False,
)
client = MontyClient(repo)
...SQLite write concern:
client = MontyClient("/db/repo",
synchronous=1,
automatic_index=False,
busy_timeout=5000)lightning is NOT the default on-disk storage, need configuration first before get client.
Newly implemented.
from montydb import set_storage, MontyClient
set_storage("/db/repo", storage="lightning") # required, to set lightning as engine
client = MontyClient("/db/repo")
# ready to goLMDB config:
[lightning]
map_size: 10485760 # Maximum size database may grow to.Optionally, You could prefix the repository path with montydb URI scheme.
client = MontyClient("montydb:///db/repo")Pymongo
bsonmay required.
-
Imports content from an Extended JSON file into a MontyCollection instance. The JSON file could be generated from
montyexportormongoexport.from montydb import open_repo, utils with open_repo("foo/bar"): utils.montyimport("db", "col", "/path/dump.json")
-
Produces a JSON export of data stored in a MontyCollection instance. The JSON file could be loaded by
montyimportormongoimport.from montydb import open_repo, utils with open_repo("foo/bar"): utils.montyexport("db", "col", "/data/dump.json")
-
Loads a binary database dump into a MontyCollection instance. The BSON file could be generated from
montydumpormongodump.from montydb import open_repo, utils with open_repo("foo/bar"): utils.montyrestore("db", "col", "/path/dump.bson")
-
Creates a binary export from a MontyCollection instance. The BSON file could be loaded by
montyrestoreormongorestore.from montydb import open_repo, utils with open_repo("foo/bar"): utils.montydump("db", "col", "/data/dump.bson")
-
Record MongoDB query results in a period of time. Requires to access database profiler.
This works via filtering the database profile data and reproduce the queries of
findanddistinctcommands.from pymongo import MongoClient from montydb.utils import MongoQueryRecorder client = MongoClient() recorder = MongoQueryRecorder(client["mydb"]) recorder.start() # Make some queries or run the App... recorder.stop() recorder.extract() {<collection_1>: [<doc_1>, <doc_2>, ...], ...}
-
Experimental, a subclass of
list, combined the common CRUD methods from Mongo's Collection and Cursor.from montydb.utils import MontyList mtl = MontyList([1, 2, {"a": 1}, {"a": 5}, {"a": 8}]) mtl.find({"a": {"$gt": 3}}) MontyList([{'a': 5}, {'a': 8}])
montydb uses uv for dependency management, task execution, builds, and publishing.
After cloning the repository, run:
uv syncThis creates a virtual environment and installs development dependencies.
uv sync
uv run pytest . --no-cov
uv run ruff check .
uv run ruff format .
uv run codespell
uv run bandit montydb -r
uv buildMost of our tests compare montydb CRUD results against real mongodb instance, therefore we must have a running mongodb before testing.
For example, if we want to test against mongo 4.4:
docker run --name monty-4.4 -p 30044:27017 -d mongo:4.4uv run pytest --storage {storage engin name} --mongodb {mongo instance url} [--use-bson]Example:
uv run pytest --storage memory --mongodb localhost:30044 --use-bsonMainly for personal skill practicing and fun.
I work in the VFX industry and some of my production needs (mostly edge-case) requires to run in a limited environment (e.g. outsourced render farms), which may have problem to run or connect a MongoDB instance. And I found this project really helps.

