Mongoclass
A basic ORM like interface for mongodb in python that uses dataclasses.
Installation
To get started, install mongoclass using pip like so.
pip install -U mongoclass
Getting Started
This section will explain the basics of how to use mongoclass. After reading this, read the API Reference for more information.
from mongoclass import MongoClassClient
client = MongoClassClient("mongoclass", "localhost:27017")
This will create a MongoClassClient
instance that exposes the features of mongoclass. MongoClassClient
inherits from pymongo.MongoClient
so you can also use it like you'd normally use pymongo.
Schemas
To create a schema (or a preferred term, mongoclass), this is all you have to do.
from dataclasses import dataclass
@client.mongoclass()
@dataclass
class User:
name: str
email: str
phone: int
country: str = "US"
This creates a User
mongoclass that belongs in the user
collection inside the default database. To create an actual User
object and have it be inserted in the database, create an instance of User
and call the .insert()
method or .save()
like so.
john = User("John Dee", "johndee@gmail.com", 5821)
insert_result = john.insert() # Works!
insert_result = john.save() # Also works!
The first line creates the user John Dee with the provided information. Notice how we didn't need to provide a country, that is because country defaults to US.
The second line inserts it to the user
collection in the default database and then returns a pymongo.InsertOneResult
What if you don't want to call insert()
or pass _insert=True
? Simple, when decorating a dataclass just pass insert_on_init=True
like so.
@client.mongoclass(insert_on_init=True)
@dataclass
class User:
...
john = ("John Dee", "johndee@gmail.com", 5821)
# John is immediately inserted
Now what if you want to insert multiple objects? Use the client.insert_classes
method.
users = [
User("John Dee", "johndee@gmail.com", 100),
User("Michael Reeves", "michaelreeves@gmail.com", 42069)
]
client.insert_classes(users)
Yes, you have to pass insert_one=True
onto client.insert_classes
in order for them to be inserted into their respective collections and databases. Under the hood, insert_one=True
will tell the method to just call the insert()
method on each object in the list.
Nested Mongoclasses
Support for nested mongoclasses was added on v0.4
By default nested is disabled for performance reasons. In order to enabled nested classes, pass nested=True
onto the mongoclass decorator.
Example
@client.mongoclass()
@dataclass
class Metadata:
age: int
phone: int
@client.mongoclass(nested=True)
@dataclass
class User:
name: str
email: str
metadata: Metadata
User("John Howards", "johnhowards@gmail.com", Metadata(23, 43123)).insert()
Once inserted in the database, the format is changed a bit so that it know how to reconstruct it back into a object once you query for it. Here's how the new format would look like.
{
"name": "John Howards",
"email": "johnhowards@gmail.com",
"metadata": {
"_nest_collection": "metadata",
"_nest_database": "main",
"data": {
"age": 23,
"phone": 43123
}
}
}
You don't need to do anything different when it comes to querying nested data. Just use the find_class
or find_classes
normally and it would automatically nest it. Check Finding Data section below for more information.
Mongoclass in a different collection
Now what if you want the User
object to belong in a different collection and database? It's simple, you just provide some extra arguments to the mongoclass()
wrapper.
@client.mongoclass("profile", "profile_list")
@dataclass
class User:
name: str
email: str
phone: int
country: str = "US"
This will create a User
schema that belongs to the profile
collection instead of user
inside the profile_list
database. By default, collections are chosen by the name of the decorated dataclass but lowered.
The second argument can also be a pymongo.Database
instance if you prefer that.
Updating Data
Any dataclass that you decorate with @client.mongoclass()
will have a update()
and .save()
method that basically allows you to update that specific object.
First, here's an example of how you would update an object or a document using .update()
that has been already been inserted.
john = User("John Dee", "johndee@gmail.com", 5821)
john.insert()
# Let's change john's country to UK
update_result, new_john = john.update(
{"$set": {"country": "UK"}},
return_new=True
)
This will update john's country to UK. As you can see, the update method simply accepts the same parameters as pymongo's update_one()
. The return_new
means it'll return the new object rather than returning the same object.
Here's an example using the .save()
method.
# For better example sake, let's imagine we added an age attribute (The last one)
john = User("John Dee", "johndee@gmail.com", 5821, 21)
john.insert()
# Let's change john's country to UK
john.name = "UK"
# Let's also change john's age to 22 by incrementing it
john.age += 1
# Now let's update this entry in the database using the .save()
update_result, new_john = john.save()
As you can see, the difference is, .save()
will basically update based on the current state of the attributes of the object.
Finding Data
To query data, mongoclass has two methods for that. client.find_class
and client.find_classes
They're kind of like pymongo's find()
and find_one()
except they return the mongoclasses that contains the data instead of just a raw document.
# Find john in the default database inside the user collection
john = client.find_class("user", {"name": "John Dee"})
The first argument points to the collection john belongs in. The second argument is the filter to use. (As same as find_one()
) Optionally, you can pass a database="database_name"
parameter to tell mongoclass what database to look at.
If you've overwritten the collection name in @client.mongoclass()
with something different, the collection you pass must be the same.
What if we're looking for multiple data?
us_residents = client.find_classes("user", {"country": "US"})
This will return a cursor object similar to pymongo's cursor. Each data in the cursor has a country of US.
Deleting
Deleting is simple. You just have to call the .delete()
method of a mongoclass like so.
delete_result = john.delete()
# Deletes john
Last updated