### Install aiomongodel Source: https://github.com/ilex/aiomongodel/blob/develop/docs/getting-started.md Install the aiomongodel library using pip. ```default pip install aiomongodel ``` -------------------------------- ### Transaction Setup Source: https://github.com/ilex/aiomongodel/blob/develop/README.rst Prepare for using transactions by creating the collection before initiating transactional operations. ```python from motor.motor_asyncio import AsyncIOMotorClient async def go(db): # create collection before using transaction await User.create_collection(db) ``` -------------------------------- ### Delete Document Example Source: https://github.com/ilex/aiomongodel/blob/develop/README.rst Example of deleting a specific document from the database using the delete method. ```python u = await User.q(db).get('Ihor') await u.delete(db) ``` -------------------------------- ### Perform Multi-Document Transactions with Motor ClientSession Source: https://context7.com/ilex/aiomongodel/llms.txt Use a Motor ClientSession with `q()` or QuerySet methods to execute operations within a transaction. Ensure the collection exists before starting the transaction. Transactions are automatically rolled back on error. ```python async def demo_transaction(db): await User.create_collection(db) # must exist before transaction async with await db.client.start_session() as s: try: async with s.start_transaction(): # All writes share the same session/transaction u = await User.q(db, session=s).create(name='charlie') await User.q(db).update_one( {User.name.s: 'charlie'}, {'$set': {User.is_active.s: False}}, session=s, ) # Instance-level methods also accept session= await u.delete(db, session=s) raise RuntimeError('Simulated failure') except RuntimeError: pass # transaction rolled back automatically # No documents were persisted count = await User.q(db).count_documents({User.name.s: 'charlie'}) assert count == 0 ``` -------------------------------- ### Async Transaction Management with aiomongodel Source: https://github.com/ilex/aiomongodel/blob/develop/docs/getting-started.md Demonstrates how to perform atomic operations using asynchronous transactions. Ensure collections are created before starting a transaction. The session object must be passed to relevant methods for them to be included in the transaction. ```python from motor.motor_asyncio import AsyncIOMotorClient async def go(db): # create collection before using transaction await User.create_collection(db) async with await db.client.start_session() as session: try: async with s.start_transaction(): # all statements that use session inside this block # will be executed in one transaction # pass session to QuerySet await User.q(db, session=session).create(name='user') # note session param # pass session to QuerySet method await User.q(db).update_one( {User.name.s: 'user'}, {'$set': {User.is_active.s: False}}, session=session) # note session usage assert await User.q(db, session).count_documents({User.name.s: 'user'}) == 1 # session could be used in document crud methods u = await User(name='user2').save(db, session=session) await u.delete(db, session=session) raise Exception() # simulate error in transaction block except Exception: # transaction was not committed assert await User.q(db).count_documents({User.name.s: 'user'}) == 0 loop = asyncio.get_event_loop() client = AsyncIOMotorClient(io_loop=loop) db = client.aiomongodel_test loop.run_until_complete(go(db)) ``` -------------------------------- ### Update Document with Query Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Use the `update` method to modify a document in the database based on a query. This example shows how to set a field and increment a value. ```python class User(Document): name = StrField() value = IntField(default=0) async def go(db): u = await User(name='xxx').save(db) await u.update(db, {'$set': {User.name.s: 'yyy'}, '$inc': {User.value.s: 1}}) ``` -------------------------------- ### Create and Save a Document with MotorQuerySet.create() Source: https://context7.com/ilex/aiomongodel/llms.txt Instantiate and save a document in a single call using Document.q(db).create(**kwargs). Ensure indexes exist before creating documents. ```python async def demo_create(db): await User.q(db).create_indexes() # ensure indexes exist first bob = await User.q(db).create(name='bob', is_active=True) print(bob._id) # 'bob' print(bob.is_active) # True post = await Post.q(db).create( title='Hello World', body='First post!', comments=[Comment(body='Nice!', author='alice')], ) print(post.title) # 'Hello World' print(len(post.comments)) # 1 ``` -------------------------------- ### MotorQuerySet.create() Source: https://context7.com/ilex/aiomongodel/llms.txt Instantiates a document from keyword arguments and immediately saves it to the database. ```APIDOC ## MotorQuerySet.create() ### Description Instantiates a document from keyword arguments and immediately saves it. This is a convenience method that combines document creation and saving into a single call. ### Method `Document.q(db).create(**kwargs)` ### Parameters - **db**: The MongoDB database connection. - **kwargs**: Keyword arguments to initialize the document fields. ### Request Example ```python async def demo_create(db): await User.q(db).create_indexes() # ensure indexes exist first bob = await User.q(db).create(name='bob', is_active=True) print(bob._id) # 'bob' print(bob.is_active) # True post = await Post.q(db).create( title='Hello World', body='First post!', comments=[Comment(body='Nice!', author='alice')], ) print(post.title) # 'Hello World' print(len(post.comments)) # 1 ``` ``` -------------------------------- ### Accessing MongoDB Field Name Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Use the '.s' property to get the MongoDB name of a field, which may differ from its Python name. ```python User.q(db).find({User.name.s: 'Francesco', User.is_admin.s: True}, {User.posts.s: 1, User._id.s: 0}) ``` -------------------------------- ### aiomongodel CRUD Operations Source: https://github.com/ilex/aiomongodel/blob/develop/README.rst Demonstrates Create, Read, Update, and Delete operations using aiomongodel. Includes creating documents with save and query, retrieving documents by ID, finding documents with filters, iterating through results, and updating documents. ```python from motor.motor_asyncio import AsyncIOMotorClient async def go(db): # create model's indexes await User.q(db).create_indexes() # CREATE # create using save # Note: if do_insert=False (default) save performs a replace # with upsert=True, so it does not raise if _id already exists # in db but replace document with that _id. u = await User(name='Alexandro').save(db, do_insert=True) assert u.name == 'Alexandro' assert u._id == 'Alexandro' assert u.is_active is True assert u.posts == [] assert u.quote is None # using query u = await User.q(db).create(name='Ihor', is_active=False) # READ # get by id u = await User.q(db).get('Alexandro') assert u.name == 'Alexandro' # find users = await User.q(db).find({User.is_active.s: True}).to_list(10) assert len(users) == 2 # using for loop users = [] async for user in User.q(db).find({User.is_active.s: False}): users.append(user) assert len(users) == 1 # in Python 3.6 an up use async comprehensions users = [user async for user in User.q(db).find({})] assert len(users) == 3 # UPDATE u = await User.q(db).get('Ihor') u.is_active = True await u.save(db) assert (await User.q(db).get('Ihor')).is_active is True # using update (without data validation) # object is reloaded from db after update. await u.update(db, {'$push': {User.posts.s: ObjectId()}}) ``` -------------------------------- ### Document Instance Methods Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Provides methods for managing individual document instances, including saving, deleting, reloading, and converting data formats. ```APIDOC ## Document Instance Methods ### *async* delete(db, session=None) Delete current object from db. ### populate_with_data(data) Populate document object with data. * **Parameters:** **data** (*dict*) – Document data in form {field_name => value}. * **Returns:** Self instance. * **Raises:** **AttributeError** – On wrong field name. ### *property* query_id ### *async* reload(db, session=None) Reload current object from mongodb. ### *async* save(db, do_insert=False, session=None) Save document in mongodb. * **Parameters:** * **db** – Database instance. * **do_insert** (*bool*) – If `True` always perform `insert_one`, else perform `replace_one` with `upsert=True`. * **session** – Motor session object. ### to_data() Return internal data of the document. * **Returns:** Data of the document. * **Return type:** OrderedDict ### to_mongo() Convert document to mongo format. ``` -------------------------------- ### Async Transaction Management with aiomongodel Source: https://github.com/ilex/aiomongodel/blob/develop/README.rst Demonstrates how to manage database transactions asynchronously using aiomongodel. Ensure all operations within the `async with s.start_transaction():` block are executed atomically. If an exception occurs, the transaction is rolled back. ```python async with await db.client.start_session() as session: try: async with s.start_transaction(): # all statements that use session inside this block # will be executed in one transaction # pass session to QuerySet await User.q(db, session=session).create(name='user') # note session param # pass session to QuerySet method await User.q(db).update_one( {User.name.s: 'user'}, {'$set': {User.is_active.s: False}}, session=session) # note session usage assert await User.q(db, session).count_documents({User.name.s: 'user'}) == 1 # session could be used in document crud methods u = await User(name='user2').save(db, session=session) await u.delete(db, session=session) raise Exception() # simulate error in transaction block except Exception: # transaction was not committed assert await User.q(db).count_documents({User.name.s: 'user'}) == 0 loop = asyncio.get_event_loop() client = AsyncIOMotorClient(io_loop=loop) db = client.aiomongodel_test loop.run_until_complete(go(db)) ``` -------------------------------- ### Querying Data with aiomongodel Source: https://github.com/ilex/aiomongodel/blob/develop/README.rst Demonstrates finding documents with projection, finding a single document, updating multiple documents, and deleting documents. ```python async def go(db): # find returns a cursor cursor = User.q(db).find({}, {'_id': 1}).skip(1).limit(2) async for user in cursor: print(user.name) assert user.is_active is None # we used projection # find one user = await User.q(db).find_one({User.name.s: 'Alexandro'}) assert user.name == 'Alexandro' # update await User.q(db).update_many( {User.is_active.s: True}, {'$set': {User.is_active.s: False}}) # delete await User.q(db).delete_many({}) ``` -------------------------------- ### Perform CRUD Operations Source: https://github.com/ilex/aiomongodel/blob/develop/docs/getting-started.md Demonstrates creating, reading, updating, and deleting documents using aiomongodel's query interface and model methods. Ensure indexes are created before performing operations. Use `save(db, do_insert=True)` for creating new documents. ```python from motor.motor_asyncio import AsyncIOMotorClient import asyncio from bson.objectid import ObjectId async def go(db): # create model's indexes await User.q(db).create_indexes() # CREATE # create using save # Note: if do_insert=False (default) save performs a replace # with upsert=True, so it does not raise if _id already exists # in db but replace document with that _id. u = await User(name='Alexandro').save(db, do_insert=True) assert u.name == 'Alexandro' assert u._id == 'Alexandro' assert u.is_active is True assert u.posts == [] assert u.quote is None # using query u = await User.q(db).create(name='Ihor', is_active=False) # READ # get by id u = await User.q(db).get('Alexandro') assert u.name == 'Alexandro' # find users = await User.q(db).find({User.is_active.s: True}).to_list(10) assert len(users) == 2 # using for loop users = [] async for user in User.q(db).find({User.is_active.s: False}): users.append(user) assert len(users) == 1 # in Python 3.6 an up use async comprehensions users = [user async for user in User.q(db).find({})] assert len(users) == 3 # UPDATE u = await User.q(db).get('Ihor') u.is_active = True await u.save(db) assert (await User.q(db).get('Ihor')).is_active is True # using update (without data validation) # object is reloaded from db after update. await u.update(db, {'$push': {User.posts.s: ObjectId()}}) # DELETE u = await User.q(db).get('Ihor') await u.delete(db) loop = asyncio.get_event_loop() client = AsyncIOMotorClient(io_loop=loop) db = client.aiomongodel_test loop.run_until_complete(go(db)) ``` -------------------------------- ### Counting Documents and Aggregation Pipelines Source: https://context7.com/ilex/aiomongodel/llms.txt Shows how to use `count_documents()` for document counts and `aggregate()` for MongoDB aggregation pipelines. `aggregate()` passes the pipeline directly to Motor, prepending `$match` if `default_query` is set. ```python async def demo_aggregate(db): total = await Post.q(db).count_documents({}) active = await User.q(db).count_documents({User.is_active.s: True}) print(f'{active}/{total}') # MongoDB aggregation pipeline pipeline = [ {'$match': {Post.views.s: {'$gt': 0}}}, {'$group': {'_id': None, 'avg_views': {'$avg': f'${Post.views.s}'}}}, ] async for doc in Post.q(db).aggregate(pipeline): print(doc['avg_views']) ``` -------------------------------- ### Define User and Post Models Source: https://github.com/ilex/aiomongodel/blob/develop/README.rst Define asynchronous models for User and Post, inheriting from aiomongodel.Document. Includes field definitions, meta options for collection names, indexes, and default sorting. Also demonstrates defining an EmbeddedDocument for comments. ```python from datetime import datetime from pymongo import IndexModel, DESCENDING from aiomongodel import Document, EmbeddedDocument from aiomongodel.fields import ( StrField, BoolField, ListField, EmbDocField, RefField, SynonymField, IntField, FloatField, DateTimeField, ObjectIdField) class User(Document): _id = StrField(regex=r'[a-zA-Z0-9_]{3, 20}') is_active = BoolField(default=True) posts = ListField(RefField('models.Post'), default=lambda: list()) quote = StrField(required=False) # create a synonym field name = SynonymField(_id) class Meta: collection = 'users' class Post(Document): # _id field will be added automatically as # _id = ObjectIdField(defalut=lambda: ObjectId()) title = StrField(allow_blank=False, max_length=50) body = StrField() created = DateTimeField(default=lambda: datetime.utcnow()) views = IntField(default=0) rate = FloatField(default=0.0) author = RefField(User, mongo_name='user') comments = ListField(EmbDocField('models.Comment'), default=lambda: list()) class Meta: collection = 'posts' indexes = [IndexModel([('created', DESCENDING)])] default_sort = [('created', DESCENDING)] class Comment(EmbeddedDocument): _id = ObjectIdField(default=lambda: ObjectId()) author = RefField(User) body = StrField() # `s` property of the fields can be used to get a mongodb string name # to use in queries assert User._id.s == '_id' assert User.name.s == '_id' # name is synonym assert Post.title.s == 'title' assert Post.author.s == 'user' # field has mongo_name assert Post.comments.body.s == 'comments.body' # compound name ``` -------------------------------- ### ListField and EmbDocField for Nested Structures Source: https://context7.com/ilex/aiomongodel/llms.txt Demonstrates how to use ListField to wrap other field types for arrays and EmbDocField to embed full documents. Shows compound dotted-path queries using the `.s` property. ```python class Tag(EmbeddedDocument): name = StrField() color = StrField(default='grey') class Article(Document): title = StrField() tags = ListField(EmbDocField(Tag), default=list, min_length=1) class Meta: collection = 'articles' async def demo_embedded(db): art = await Article.q(db).create( title='Deep Dive', tags=[Tag(name='python', color='blue'), Tag(name='mongodb')], ) print(art.tags[0].name) # 'python' print(art.tags[1].color) # 'grey' (default) # Compound field name for querying assert Article.tags.name.s == 'tags.name' results = await Article.q(db).find( {Article.tags.name.s: 'python'} ).to_list(10) print(len(results)) # 1 ``` -------------------------------- ### Models Inheritance with Same Collection Source: https://github.com/ilex/aiomongodel/blob/develop/README.rst Shows how to define multiple models that share the same MongoDB collection, using meta options and class methods for custom loading logic. ```python class Mixin: is_active = BoolField(default=True) class User(Mixin, Document): _id = StrField() role = StrField() name = SynonymField(_id) class Meta: collection = 'users' @classmethod def from_mongo(cls, data): # create appropriate model when loading from db if data['role'] == 'customer': return super(User, Customer).from_mongo(data) if data['role'] == 'admin': return super(User, Admin).from_mongo(data) class Customer(User): role = StrField(default='customer', choices=['customer']) # overwrite role field address = StrField() class Meta: collection = 'users' default_query = {User.role.s: 'customer'} class Admin(User): role = StrField(default='admin', choices=['admin']) # overwrite role field rights = ListField(StrField(), default=lambda: list()) class Meta: collection = 'users' default_query = {User.role.s: 'admin'} ``` -------------------------------- ### Query Multiple Documents with MotorQuerySet.find() Source: https://context7.com/ilex/aiomongodel/llms.txt Use `find()` to retrieve multiple documents. It supports async iteration, `to_list()`, `skip()`, `limit()`, and other Motor cursor methods. You can specify a query, projection, and sort order. ```python async def demo_find(db): # Collect up to 20 active users into a list active_users = await User.q(db).find({User.is_active.s: True}).to_list(20) print(len(active_users)) # Async for loop async for user in User.q(db).find({User.is_active.s: False}): print(user.name) # Async comprehension (Python 3.6+) names = [u.name async for u in User.q(db).find({})] # With projection, skip, and limit cursor = User.q(db).find({}, {'_id': 1}).skip(2).limit(5) async for user in cursor: print(user._id) # other fields are None due to projection ``` -------------------------------- ### Manage Database Indexes with create_indexes() Source: https://context7.com/ilex/aiomongodel/llms.txt Call `create_indexes()` on a MotorQuerySet to create indexes defined in `Meta.indexes`. This method is idempotent and safe to call on application startup. Indexes are not created automatically. ```python from pymongo import IndexModel, ASCENDING, DESCENDING class Event(Document): name = StrField() created = DateTimeField(default=lambda: datetime.utcnow()) user_id = StrField() class Meta: collection = 'events' indexes = [ IndexModel([('created', DESCENDING)]), IndexModel([('user_id', ASCENDING), ('created', DESCENDING)]), ] async def startup(db): await Event.q(db).create_indexes() # idempotent; safe to call on every start ``` -------------------------------- ### Model Inheritance Source: https://github.com/ilex/aiomongodel/blob/develop/docs/getting-started.md Create model hierarchies by inheriting from `aiomongodel.Document` or `aiomongodel.EmbeddedDocument`. Fields are inherited, but meta options are not. ```python class Mixin: value = IntField() class Parent(Document): name = StrField() class Child(Mixin, Parent): # also has value and name fields rate = FloatField() class OtherChild(Child): # also has rate and name fields value = FloatField() # overwrite value field from Mixin class SubDoc(Mixin, EmbeddedDocument): # has value field pass ``` -------------------------------- ### Import Class by Path Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Dynamically imports a class from its absolute import path. The imported class is cached for subsequent calls. Ensure the path is correct to avoid ImportErrors. ```python Document = import_class('aiomongodel.document.Document') ``` -------------------------------- ### Implement Model Inheritance and Polymorphism Source: https://context7.com/ilex/aiomongodel/llms.txt Override `from_mongo()` on a base class to return the correct subclass when loading documents. Fields are inherited, but `Meta` options are not. Use `Meta.default_query` to automatically apply filters for subclasses. ```python class Animal(Document): _id = StrField() kind = StrField() name = SynonymField(_id) class Meta: collection = 'animals' @classmethod def from_mongo(cls, data): if data.get('kind') == 'dog': return super(Animal, Dog).from_mongo(data) if data.get('kind') == 'cat': return super(Animal, Cat).from_mongo(data) return super().from_mongo(data) class Dog(Animal): breed = StrField(required=False) class Meta: collection = 'animals' default_query = {Animal.kind.s: 'dog'} class Cat(Animal): indoor = BoolField(default=True) class Meta: collection = 'animals' default_query = {Animal.kind.s: 'cat'} async def demo_poly(db): await Dog.q(db).create(name='rex', kind='dog', breed='Labrador') await Cat.q(db).create(name='kitty', kind='cat', indoor=False) # default_query is applied automatically dogs = await Dog.q(db).find({}).to_list(10) cats = await Cat.q(db).find({}).to_list(10) assert all(isinstance(d, Dog) for d in dogs) assert all(isinstance(c, Cat) for c in cats) ``` -------------------------------- ### Define User Document Model Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Define a User document inheriting from aiomongodel.Document, specifying fields, collection name, and indexes. Indexes are not created automatically and require explicit creation using MotorQuerySet.create_indexes. ```python from pymongo import IndexModel, ASCENDING, DESCENDING class User(Document): name = StrField(regex=r'^[a-zA-Z]{6,20}$') is_active = BoolField(default=True) created = DateTimeField(default=lambda: datetime.utcnow()) class Meta: # define a collection name collection = 'users' # define collection indexes. Use # await User.q(db).create_indexes() # to create them on application startup. indexes = [ IndexModel([('name', ASCENDING)], unique=True), IndexModel([('created', DESCENDING)])] # order by `created` field by default default_sort = [('created', DESCENDING)] ``` -------------------------------- ### Meta Class Options Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Defines metadata for a Document, including collection name, indexes, query settings, and field configurations. ```APIDOC ### *class* aiomongodel.document.Meta Storage for Document meta info. #### collection_name Name of the document’s db collection (note that it should be specified as `collection` Meta class attribute). #### indexes List of `pymongo.IndexModel` for collection. #### queryset Query set class to query documents. #### default_query Each query in query set will be extended using this query through `$and` operator. #### default_sort Default sort expression to order documents in `find`. #### fields OrderedDict of document fields as `{field_name => field}`. #### fields_synonyms Dict of synonyms for field as `{field_name => synonym_name}`. #### codec_options Collection’s codec options. #### read_preference Collection’s read preference. #### write_concern Collection’s write concern. #### read_concern Collection’s read concern. #### OPTIONS *= {'codec_options', 'collection', 'default_query', 'default_sort', 'fields', 'fields_synonyms', 'indexes', 'queryset', 'read_concern', 'read_preference', 'write_concern'}* #### collection(db) Get collection for documents. ### Parameters * **db**: Database object. ### Returns Collection object. ``` -------------------------------- ### Field Methods Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Methods available for field objects, including from_data, from_mongo, s property, and to_mongo. ```APIDOC ## Field Methods ### Description Methods available for field objects. ### Methods #### from_data(value) Convert value from user provided data to field type. * **Parameters:** **value** – Value provided by user. * **Returns:** Converted value or value as is if error occured. If value is `None` return `None`. #### from_mongo(value) Convert value from mongo format to python field format. #### *property* s Return mongodb name of the field. This property can be used wherever mongodb field’s name is required. Example: ```python User.q(db).find({User.name.s: 'Francesco', User.is_admin.s: True}, {User.posts.s: 1, User._id.s: 0}) ``` #### NOTE Field’s `name` and `mongo_name` could be different so `User.is_admin.s` could be for example `'isadm'`. #### to_mongo(value) Convert value to mongo format. ``` -------------------------------- ### Save a Document Instance with Document.save() Source: https://context7.com/ilex/aiomongodel/llms.txt Persist a document instance to MongoDB using save(). By default, it performs replace_one with upsert=True. Use do_insert=True for insert_one, which raises on duplicate _id. Reload the object to confirm changes. ```python async def demo_save(db): # Insert a new document (raises DuplicateKeyError if _id exists) alice = await User(name='alice', is_active=True).save(db, do_insert=True) print(alice._id) # 'alice' print(alice.is_active) # True # Mutate and upsert (default behaviour – safe for updates too) alice.is_active = False await alice.save(db) # Reload the object from the database to confirm await alice.reload(db) print(alice.is_active) # False client = AsyncIOMotorClient() asyncio.get_event_loop().run_until_complete(demo_save(client.mydb)) ``` -------------------------------- ### Document Definition and Meta Options Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Defines the base Document class and its associated Meta options for configuring collection name, indexes, and query behavior. ```APIDOC ## Document Class ### Description Base class for documents. Each document class should be defined by inheriting from this class and specifying fields and optionally meta options using an internal `Meta` class. ### Fields Fields are inherited from base classes and can be overwritten. Meta options are NOT inherited. ### Meta Options Possible meta options for `class Meta`: - `collection`: Name of the document’s db collection. - `indexes`: List of `pymongo.IndexModel` for collection. - `queryset`: Query set class to query documents. - `default_query`: Each query in query set will be extended using this query through `$and` operator. - `default_sort`: Default sort expression to order documents in `find`. - `codec_options`: Collection’s codec options. - `read_preference`: Collection’s read preference. - `write_concern`: Collection’s write concern. - `read_concern`: Collection’s read concern. ### NOTE Indexes are not created automatically. Use `MotorQuerySet.create_indexes` method to create document’s indexes. ### Example ```python from pymongo import IndexModel, ASCENDING, DESCENDING class User(Document): name = StrField(regex=r'^[a-zA-Z]{6,20}$') is_active = BoolField(default=True) created = DateTimeField(default=lambda: datetime.utcnow()) class Meta: collection = 'users' indexes = [ IndexModel([('name', ASCENDING)], unique=True), IndexModel([('created', DESCENDING)])] default_sort = [('created', DESCENDING)] class ActiveUser(User): is_active = BoolField(default=True, choices=[True]) class Meta: collection = 'users' default_query = {'is_active': True} ``` ### Initialization Initializes a document. * **Parameters:** * **_empty** (*bool*) – If True return an empty document without setting any field. * **&&kwargs** – Fields values to set. Each key should be a field name not a mongo name of the field. ``` -------------------------------- ### IntField Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Represents an integer field. ```APIDOC ### *class* aiomongodel.fields.IntField(**kwargs) Integer field. Create int field. ``` -------------------------------- ### Field Parameters Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Common parameters for defining fields in aiomongodel, such as required, default, mongo_name, name, allow_none, verbose_name, and choices. ```APIDOC ## Field Parameters ### Description Common parameters for defining fields in aiomongodel. ### Parameters #### Path Parameters - **required** (*bool*) – Is field required. Defaults to `True`. - **default** – Default value for a field. When document has no value for field in `__init__` it try to use default value (if it is not `_Empty`). Defaults to `_Empty`. #### NOTE Default value is ignored if field is not required. #### NOTE Default can be a value or a callable with no arguments. - **mongo_name** (*str*) – Name of the field in MongoDB. Defaults to `None`. #### NOTE If `mongo_name` is None it is set to `name` of the field. - **name** (*str*) – Name of the field. Should not be used explicitly as it is set by metaclass. Defaults to `None`. - **allow_none** (*bool*) – Can field be assign with `None`. Defaults to `False`. - **verbose_name** (*str*) – Verbose field name for met information about field. Defaults to `None`. - **choices** (*dict* *,* *set*) – Possible values for field. If it is a `dict`, keys should be possible values. To preserve values order use `collections.OrderedDict`. Defaults to `None`. #### NOTE If `choices` are given then other constraints are ignored. ``` -------------------------------- ### Querying with aiomongodel Source: https://github.com/ilex/aiomongodel/blob/develop/docs/getting-started.md Perform find, find_one, update, and delete operations using the query interface. Use projections to select specific fields and `is_active.s` for attribute access in queries. ```python async def go(db): # find returns a cursor cursor = User.q(db).find({}, {'_id': 1}).skip(1).limit(2) async for user in cursor: print(user.name) assert user.is_active is None # we used projection # find one user = await User.q(db).find_one({User.name.s: 'Alexandro'}) assert user.name == 'Alexandro' # update await User.q(db).update_many( {User.is_active.s: True}, {'$set': {User.is_active.s: False}}) # delete await User.q(db).delete_many({}) ``` -------------------------------- ### Fetch a Document by _id with MotorQuerySet.get() Source: https://context7.com/ilex/aiomongodel/llms.txt Retrieve a document by its _id using MotorQuerySet.get(_id). This method calls find_one and raises DocumentNotFoundError if no matching document is found. ```python from aiomongodel.errors import DocumentNotFoundError async def demo_get(db): user = await User.q(db).get('alice') print(user.name) # 'alice' try: await User.q(db).get('nobody') except DocumentNotFoundError: print('User not found') # User not found ``` -------------------------------- ### EmbeddedDocument Initialization Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Initializes an EmbeddedDocument instance. Can be used to create an empty document or populate it with initial data. ```APIDOC ### *class* aiomongodel.EmbeddedDocument Initialize document. ### Parameters * **_empty** (*bool*) – If True return an empty document without setting any field. * **kwargs** – Fields values to set. Each key should be a field name not a mongo name of the field. ``` -------------------------------- ### Define and Validate Model Source: https://github.com/ilex/aiomongodel/blob/develop/docs/getting-started.md Define a model with fields and their constraints. Use the `validate()` method to check data integrity. Note that model creation does not raise errors for invalid data; validation must be called explicitly. ```python class Model(Document): name = StrField(max_length=7) value = IntField(gt=5, lte=13) data = FloatField() def go(): m = Model(name='xxx', value=10, data=1.6) # validate data # should not raise any error m.validate() # invalid data # note that there are no errors while creating # model with invalid data invalid = Model(name='too long string', value=0) try: invalid.validate() except aiomongodel.errors.ValidationError as e: assert e.as_dict() == { 'name': 'length is greater than 7', 'value': 'value should be greater than 5', 'data': 'field is required' } # using translation - you can translate messages # to your language or modify them translation = { "field is required": "This field is required", "length is greater than {constraint}": ("Length of the field " "is greater than " "{constraint} characters"), # see all error messages in ValidationError docs # for missed messages default messages will be used } assert e.as_dict(translation=translation) == { 'name': 'Length of the field is greater than 7 characters', 'value': 'value should be greater than 5', 'data': 'This field is required' } ``` -------------------------------- ### Query Single Document with MotorQuerySet.find_one() Source: https://context7.com/ilex/aiomongodel/llms.txt Use `find_one()` to retrieve the first matching document. It raises `DocumentNotFoundError` if no document matches the query. ```python async def demo_find_one(db): from aiomongodel.errors import DocumentNotFoundError user = await User.q(db).find_one({User.name.s: 'alice'}) print(user.is_active) # True try: await User.q(db).find_one({User.is_active.s: False, User.name.s: 'ghost'}) except DocumentNotFoundError: print('No match') ``` -------------------------------- ### Document Class Methods Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Provides methods for interacting with the MongoDB collection associated with a document, such as retrieving the collection object, creating documents, and querying. ```APIDOC ## Document Class Methods ### *classmethod* coll(db) Return raw collection object. * **Parameters:** **db** – Motor database object. * **Returns:** Raw Motor collection object. * **Return type:** MotorCollection ### *async classmethod* create(db, session=None, **kwargs) Create document in mongodb. * **Parameters:** * **db** – Database instance. * **session** – Motor session object. * **&&kwargs** – Document’s fields values. * **Returns:** Created document instance. * **Raises:** [**ValidationError**](#aiomongodel.errors.ValidationError) – If some fields are not valid. ### *async classmethod* create_collection(db, session=None) Create collection for documents. * **Parameters:** **db** – Database object. * **Returns:** Collection object. ### *classmethod* from_data(data) Create document from user provided data. * **Parameters:** **data** (*dict*) – Data dict in form {field_name => value}. * **Returns:** Document isinstance. ### *classmethod* from_mongo(data) Create document from mongo data. * **Parameters:** **data** (*dict*) – SON data loaded from mongodb. * **Returns:** Document instance. ### *classmethod* q(db, session=None) Return queryset object. * **Parameters:** * **db** – Motor database object. * **session** – Motor client session object. * **Returns:** Queryset object. * **Return type:** [MotorQuerySet](#aiomongodel.queryset.MotorQuerySet) ``` -------------------------------- ### Define and Validate a Model Source: https://github.com/ilex/aiomongodel/blob/develop/README.rst Define a model with fields and use the validate method to check data integrity. Invalid data is only caught during validation, not during model instantiation. ```python class Model(Document): name = StrField(max_length=7) value = IntField(gt=5, lte=13) data = FloatField() def go(): m = Model(name='xxx', value=10, data=1.6) # validate data # should not raise any error m.validate() # invalid data # note that there are no errors while creating # model with invalid data invalid = Model(name='too long string', value=0) try: invalid.validate() except aiomongodel.errors.ValidationError as e: assert e.as_dict() == { 'name': 'length is greater than 7', 'value': 'value should be greater than 5', 'data': 'field is required' } # using translation - you can translate messages # to your language or modify them translation = { "field is required": "This field is required", "length is greater than {constraint}": ("Length of the field " "is greater than " "{constraint} characters"), # see all error messages in ValidationError docs # for missed messages default messages will be used } assert e.as_dict(translation=translation) == { 'name': 'Length of the field is greater than 7 characters', 'value': 'value should be greater than 5', 'data': 'This field is required' } ``` -------------------------------- ### MotorQuerySet.find() Source: https://context7.com/ilex/aiomongodel/llms.txt Queries multiple documents from the database and returns a MotorQuerySetCursor. Supports async iteration and various cursor methods. ```APIDOC ## MotorQuerySet.find() ### Description Queries multiple documents based on the provided query and projection. Returns a cursor that supports asynchronous iteration and other cursor methods. ### Method `find(query, projection, sort=None)` ### Parameters - **query** (dict) - The MongoDB query filter. - **projection** (dict, optional) - The projection document to specify which fields to include or exclude. - **sort** (optional) - Sorting criteria. ### Usage Examples ```python # Collect up to 20 active users into a list active_users = await User.q(db).find({User.is_active.s: True}).to_list(20) # Async for loop async for user in User.q(db).find({User.is_active.s: False}): print(user.name) # Async comprehension names = [u.name async for u in User.q(db).find({})] # With projection, skip, and limit cursor = User.q(db).find({}, {'_id': 1}).skip(2).limit(5) async for user in cursor: print(user._id) ``` ``` -------------------------------- ### SynonymField Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Creates a synonym name for an existing field in a document, allowing for alternative access to the same data. ```APIDOC ## class aiomongodel.fields.SynonymField ### Description Create synonym name for real field. Create synonym for real document’s field. ### Parameters * **original_field** - Field instance or string name of field. ### Example ```python class Doc(Document): _id = StrField() name = SynonymField(_id) class OtherDoc(Document): # _id field will be added automaticly. obj_id = SynonymField('_id') ``` ``` -------------------------------- ### aiomongodel.utils.import_class Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Imports a class by its absolute import path and caches it for future use. ```APIDOC ## aiomongodel.utils.import_class(absolute_import_path) ### Description Import class by its path. Class is stored in cache after importing. ### Example ```python Document = import_class('aiomongodel.document.Document') ``` ### Parameters * **absolute_import_path** (*str*) - Absolute path for class to import. ### Returns Class object. ### Return type type ### Raises * **ImportError** - If class can’t be imported by its path. ``` -------------------------------- ### MotorQuerySet.get() Source: https://context7.com/ilex/aiomongodel/llms.txt Fetches a single document from the database based on its `_id`. ```APIDOC ## MotorQuerySet.get() ### Description Fetches a single document from the database by its `_id`. It calls `find_one({'_id': ...})` and raises `DocumentNotFoundError` if no matching document is found. ### Method `get(_id)` ### Parameters - **_id**: The unique identifier of the document to retrieve. ### Request Example ```python from aiomongodel.errors import DocumentNotFoundError async def demo_get(db): user = await User.q(db).get('alice') print(user.name) # 'alice' try: await User.q(db).get('nobody') except DocumentNotFoundError: print('User not found') # User not found ``` ``` -------------------------------- ### Document.save() Source: https://context7.com/ilex/aiomongodel/llms.txt Persists a Document instance to MongoDB. By default, it performs a 'replace_one' with 'upsert=True'. Use 'do_insert=True' for 'insert_one'. ```APIDOC ## Document.save() ### Description Persists a Document instance to MongoDB. By default, it performs `replace_one` with `upsert=True`; pass `do_insert=True` to use `insert_one` (raises on duplicate `_id`). ### Method `save(db, do_insert=False, session=None)` ### Parameters - **db**: The MongoDB database connection. - **do_insert** (bool): If True, uses `insert_one`. Defaults to False. - **session**: An optional session object for transactions. ### Request Example ```python async def demo_save(db): # Insert a new document (raises DuplicateKeyError if _id exists) alice = await User(name='alice', is_active=True).save(db, do_insert=True) print(alice._id) # 'alice' print(alice.is_active) # True # Mutate and upsert (default behaviour – safe for updates too) alice.is_active = False await alice.save(db) # Reload the object from the database to confirm await alice.reload(db) print(alice.is_active) # False ``` ``` -------------------------------- ### Define ActiveUser Document Model Source: https://github.com/ilex/aiomongodel/blob/develop/docs/api/index.md Define an ActiveUser document inheriting from User, overriding the is_active field and specifying a default query to filter for active users only. This ensures that queries on ActiveUser implicitly include the 'is_active': True condition. ```python class ActiveUser(User): is_active = BoolField(default=True, choices=[True]) class Meta: collection = 'users' # specify a default query to work ONLY with # active users. So for example # await ActiveUser.q(db).count({}) # will count ONLY active users. default_query = {'is_active': True} ```