Mongomantic = Pymongo + Pydantic
Mongomantic is a lightweight python MongoDB ORM based on Pydantic and PyMongo, heavily inspired by Mongoengine.
from mongomantic import BaseRepository, MongoDBModel, connect
connect("localhost:27017", "test_db") # Setup mongodb connection
class User(MongoDBModel):
first_name: str
last_name: str
class UserRepository(BaseRepository):
class Meta: # Required internal class
model = User # Define model type
collection = "user" # Define collection name
user = User(first_name="John", last_name="Smith")
user = UserRepository.save(user) # PyMongo wrapping classmethods
user.id # ObjectId that was saved
pip install mongomantic
To connect to your database, a connect function similar to mongoengine is provided.
from mongomantic import connect
connect("localhost:27017", "test_db") # Setup mongodb connection
The BaseRepository class wraps around MongoDBModel, providing functions to save models into a collection, retrieve models, create indexes, and use the aggregation pipeline syntax on the collection.
To implement a new repository, you must first inherit from BaseRepository and provide an internal Meta class to specify the model and collection being used.
class UserRepository(BaseRepository):
class Meta:
model = User
collection = "user"
And that's it! You can now access repository CRUD operations and more. More details found in the Repositories guide.
Adding indexes is simple using the Mongomantic Index model:
class UserRepository(BaseRepository):
class Meta:
model = User
collection = "user"
indexes = [
Index(fields=["+first_name"]),
Index(fields=["+first_name", "-last_name"], unique=True)
]
For production use, you can either handle the errors thrown by BaseRepository in case of errors on your own, or you can use SafeRepository which handles all the errors for you and logs them, while returning meaningful safe values like None
and []
. Usage is exactly similar to using BaseRepository.
from mongomantic import SafeRepository, MongoDBModel, connect
connect("localhost:27017", "test_db") # Setup mongodb connection
class User(MongoDBModel):
first_name: str
last_name: str
class UserRepository(SafeRepository):
class Meta: # Required internal class
model = User # Define model type
collection = "user" # Define collection name
user = UserRepository.get(id="123") # DoesNotExist error handled
assert user is None
Similar to this example, all other errors are handled.
Mongomantic can be kept as a simple wrapper around PyMongo, or developed into a miniature version of Mongoengine that's built on Pydantic. The first direction would result in the following API:
# Direct pymongo wrapper
users = UserRepository.find({"$and": [{"age": {"$gt": 12}}, {"name": "John"}]})
# But matches can be done as keyword arguments
john = UserRepository.find(name="John")
On the other hand, a more complex version of Mongomantic could lead to:
# More Pythonic way of writing queries
users = UserRepository.find(User.age > 12, name="John")
# Matches still compact
john = UserRepository.find(name="John")
Please submit your vote below.
Simple PyMongo Wrapper - Prefer speed and native mongodb filters More Complex Wrapper - Pythonic Filters
- Documentation
- Basic API similar to mongoengine, without any queryset logic
- Built on Pydantic models, no other schema required
- BaseRepository responsible for all operations (instead of the model itself)
- SafeRepository derived from BaseRepository with all errors handled
- Repository/model plugin framework (ex. SyncablePlugin, TimestampedPlugin, etc.)
- Wrapper for aggregation pipelines
- Mongomock tests
- Flexible connect() function wrapper around PyMongo client (aliases, replica sets, retry writes, etc.)
- Clean up imports and expose essentials in main file
This project is licensed under the terms of the MIT
license. See LICENSE for more details.
@misc{mongomantic,
author = {mongomantic},
title = {A MongoDB Python ORM, built on Pydantic and PyMongo.},
year = {2021},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/RamiAwar/mongomantic}}
}
This project was generated with python-package-template
.