Getting Started

Installing

MotorEngine can be easily installed with pip, using:

$ pip install motorengine

If you wish to install it from the source code, you can install it using:

$ pip install https://github.com/heynemann/motorengine/archive/master.zip

Connecting to a Database

motorengine.connection.connect(db, alias='default', **kwargs)

Connect to the database specified by the ‘db’ argument.

Connection settings may be provided here as well if the database is not running on the default port on localhost. If authentication is needed, provide username and password arguments as well.

Multiple databases are supported by using aliases. Provide a separate alias to connect to a different instance of mongod.

Extra keyword-arguments are passed to Motor when connecting to the database.

# instantiate tornado server and apps so we get io_loop instance

io_loop = tornado.ioloop.IOLoop.instance()
connect("test", host="localhost", port=27017, io_loop=io_loop)  # you only need to keep track of the
                                                               # DB instance if you connect to multiple databases.

Modeling a Document

class motorengine.document.Document(_is_partly_loaded=False, _reference_loaded_fields=None, **kw)

Base class for all documents specified in MotorEngine.

class User(Document):
    first_name = StringField(required=True)
    last_name = StringField(required=True)

class Employee(User):
    employee_id = IntField(required=True)

Creating a new instance

BaseDocument.save(**kwargs)

Creates or updates the current instance of this document.

Due to the asynchronous nature of MotorEngine, you are required to handle saving in a callback (or using yield method with tornado.concurrent).

def create_employee():
    emp = Employee(first_name="Bernardo", last_name="Heynemann", employee_id=1532)
    emp.save(handle_employee_saved)

def handle_employee_saved(emp):
    try:
        assert emp is not None
        assert emp.employee_id == 1532
    finally:
        io_loop.stop()

io_loop.add_timeout(1, create_employee)
io_loop.start()

Updating an instance

BaseDocument.save(**kwargs)

Creates or updates the current instance of this document.

Updating an instance is as easy as changing a property and calling save again:

def update_employee():
    emp = Employee(first_name="Bernardo", last_name="Heynemann", employee_id=1532)
    emp.save(handle_employee_created)

def handle_employee_created(emp):
    emp.employee_id = 1534
    emp.save(handle_employee_updated)

def handle_employee_updated(emp):
    try:
        assert emp.employee_id == 1534
    finally:
        io_loop.stop()

io_loop.add_timeout(1, update_employee)
io_loop.start()

Getting an instance

QuerySet.get(**kwargs)

Gets a single item of the current queryset collection using it’s id.

In order to query a different database, please specify the alias of the database to query.

To get an object by id, you must specify the ObjectId that the instance got created with. This method takes a string as well and transforms it into a bson.objectid.ObjectId.

def create_employee():
    emp = Employee(first_name="Bernardo", last_name="Heynemann", employee_id=1538)
    emp.save(handle_employee_saved)

def handle_employee_saved(emp):
    Employee.objects.get(emp._id, callback=handle_employee_loaded)  # every object in MotorEngine has an
                                                                    # _id property with its ObjectId.

def handle_employee_loaded(emp):
    try:
        assert emp is not None
        assert emp.employee_id == 1538
    finally:
        io_loop.stop()

io_loop.add_timeout(1, create_employee)
io_loop.start()

Querying collections

To query a collection in mongo, we use the find_all method.

QuerySet.find_all(**kwargs)

Returns a list of items in the current queryset collection that match specified filters (if any).

In order to query a different database, please specify the alias of the database to query.

Usage:

User.objects.find_all(callback=handle_all_users)

def handle_all_users(result):
    # do something with result
    # result is None if no users found
    pass

If you want to filter a collection, just chain calls to filter:

QuerySet.filter(*arguments, **kwargs)

Filters a queryset in order to produce a different set of document from subsequent queries.

Usage:

User.objects.filter(first_name="Bernardo").filter(last_name="Bernardo").find_all(callback=handle_all)
# or
User.objects.filter(first_name="Bernardo", starting_year__gt=2010).find_all(callback=handle_all)

The available filter options are the same as used in MongoEngine.

To limit a queryset to just return a maximum number of documents, use the limit method:

QuerySet.limit(limit)

Limits the number of documents to return in subsequent queries.

Usage:

User.objects.limit(10).find_all(callback=handle_all)  # even if there are 100s of users,
                                                      # only first 10 will be returned

Ordering the results is achieved with the order_by method:

QuerySet.order_by(field_name, direction=1)

Specified the order to be used when returning documents in subsequent queries.

Usage:

from motorengine import DESCENDING  # or ASCENDING

User.objects.order_by('first_name', direction=DESCENDING).find_all(callback=handle_all)

All of these options can be combined to really tune how to get items:

def create_employee():
    emp = Employee(first_name="Bernardo", last_name="Heynemann", employee_id=1538)
    emp.save(handle_employee_saved)

def handle_employee_saved(emp):
  # return the first 10 employees ordered by last_name that joined after 2010
  Employee.objects \
          .limit(10) \
          .order_by("last_name") \
          .filter(last_name="Heynemann") \
          .find_all(callback=handle_employees_loaded)

def handle_employees_loaded(employees):
    try:
        assert len(employees) > 0
        assert employees[0].last_name == "Heynemann"
    finally:
        io_loop.stop()

io_loop.add_timeout(1, create_employee)
io_loop.start()

Counting documents in collections

QuerySet.count(**kwargs)

Returns the number of documents in the collection that match the specified filters, if any.

def get_employees():
  Employee.objects.count(callback=handle_count)

def handle_count(number_of_employees):
    try:
        assert number_of_employees == 0
    finally:
        io_loop.stop()

io_loop.add_timeout(1, get_employees)
io_loop.start()