Welcome to OmMongo’s documentation!

Introduction

OmMongo is a layer on top of the Python MongoDB driver which adds client-side schema definitions, an easier to work with and programmatic query language, and a Document-Object mapper which allows python objects to be saved and loaded into the database in a type-safe way.

An explicit goal of this project is to be able to perform as many operations as possible without having to perform a load/save cycle since doing so is both significantly slower and more likely to cause data loss.

There’s more detail in the tutorial, but a small example is on this page below the contents of the documentation.

A Tour of OmMongo’s Features

Object-Document Mapping

Turn MongoDB documents into Python objects and vice-versa, add schemas and validatation to your models, and allow the separation of the python and mongo representations of your data.

  • Support for all of the basic mongo types.
  • Separate Python and Mongo names. Field and collection names can be overridden.
  • Indexing on dict keys. MA provides a dict-like field which can have arbitrary key and value types as well as allowing indexing on the keys — not normally possible in Mongo. See: KVField
  • Computed values, generate from other fields. See: ComputedField
  • Created and Modified fields based on the computed fields which record the date something was first created or last updated.
  • Timezone support. A timezone can be passed using pytz and all dates will have timezone data attached and be converted to the given timezone.
  • User-defined validation — Provide your own validation functions for simple validations of fields. See Field
  • User-defined fields — For more customization, entirely new fields can be created
  • A field that can hold arbitrary values: AnythingField
  • Validation happens at assignment time, so you’ll know exactly where
  • Indexes are defined on the class

Sessions and Query Language

  • Type-safe queries. Queries are validated to make sure the values passed are allowed in the query fields.

  • Faux-Transactions. When using the session with the with statement updates are accumulated until the block is done, making it much less likely that a python error will leave your database in a bad state.

  • Automatically Calculated Updates — The session object has an ommongo.session.Session.update() function which determines which fields are dirty and will execute the appropriate update operations to update the object in the database.

  • Drop into raw Mongo. Most functions will accept raw pymongo instead of the ommongo objects. Type safety will be maintained either way

    For example:

    session.query('SomeClass').filter(SomeClass.name == foo).limit(5)
    

    is perfectly valid, as is:

    session.query(SomeClass).filter({'name':'foo'})
    

Installation

pip install OmMongo

You can also download the source code from the Python Package index or GitHub:

The source code is available at: https://github.com/bapakode/OmMongo

The PyPi page is located here: https://pypi.python.org/pypi/OmMongo/

Examples

>>> from ommongo.session import Session
>>> from ommongo.document import Document, Index
>>> from ommongo.fields import *
>>> # Subclasses of Document both provide the mapping needed for
... # queries as well as the classes for loading/saving objects.
... class User(Document):
...     config_collection_name = 'users'
...
...     # Setting the possible values by using fields
...     first_name = StringField()
...     last_name = StringField()
...     age = IntField(min_value=0, required=False)
...
...     # db_field allows a different DB field name than the one on the
...     # python object
...     email = StringField(db_field='email_address')
...     bio = StringField(max_length=1000, required=False)
...
...     # A computed field decorator allows values
...     @computed_field(SetField(StringField()), deps=[bio])
...     def keywords(obj):
...         return set(obj.get('bio','').split(' '))
...
...     kw_index = Index().ascending('keywords')
...     name_index = Index().descending('first_name').ascending('last_name')
...     email_index = Index().descending('email').unique()
...
...     def __eq__(self, other):
...         return self.email == other.email
...
...     def __repr__(self):
...         return 'User(email="%s")' % self.email
...
>>> me = User(first_name='Bapak', last_name='Kode', email='opensource@bapakode.org',
...     bio='Bapakode is the author of OmMongo')
>>>
>>> me.keywords
set(['author', 'of', 'is', 'Bapakode', 'OmMongo', 'the'])
>>>
>>> # This connections to the DB and starts the session
... session = Session.connect('ommongo-intro')
>>> session.clear_collection(User) # clear previous runs of this code!
>>>
>>> # Insert on a session will infer the correct collection and push the object
... # into the database
... session.save(me)
>>> set(['author', 'of', 'is', 'Bapakode', 'OmMongo', 'the'])
>>>
>>> # Get a user with me's email address and OmMongo in their bio (via keywords)
... db_user = session.query(User).filter(User.email == 'opensource@bapakode.org').in_(User.keywords, 'OmMongo').one()
>>>
>>> db_user == me
True
>>>
>>> # Using filter_by for simple equality checking is easier
... session.query(User).filter_by(email='opensource@bapakode.org').in_(User.keywords, 'OmMongo').one()
User(email="opensource@bapakode.org")
>>>
>>> # It's also possible to do raw mongo filtering
... session.query(User).filter({'email':'opensource@bapakode.org', 'keywords':{'$in':['OmMongo']}}).one()
User(email="opensource@bapakode.org")
>>>

Indices and tables