========== User Guide ========== .. _guide-connecting: Installing ========== MongoEngine is available on PyPI, so to use it you can use :program:`easy_install` .. code-block:: console # easy_install mongoengine Alternatively, if you don't have setuptools installed, `download it from PyPi `_ and run .. code-block:: console # python setup.py install Connecting to MongoDB ===================== To connect to a running instance of :program:`mongod`, use the :func:`~mongoengine.connect` function. The first argument is the name of the database to connect to. If the database does not exist, it will be created. If the database requires authentication, :attr:`username` and :attr:`password` arguments may be provided:: from mongoengine import connect connect('project1', username='webapp', password='pwd123') By default, MongoEngine assumes that the :program:`mongod` instance is running on **localhost** on port **27017**. If MongoDB is running elsewhere, you may provide :attr:`host` and :attr:`port` arguments to :func:`~mongoengine.connect`:: connect('project1', host='192.168.1.35', port=12345) Defining documents ================== In MongoDB, a **document** is roughly equivalent to a **row** in an RDBMS. When working with relational databases, rows are stored in **tables**, which have a strict **schema** that the rows follow. MongoDB stores documents in **collections** rather than tables - the principle difference is that no schema is enforced at a database level. Defining a document's schema ---------------------------- MongoEngine allows you to define schemata for documents as this helps to reduce coding errors, and allows for utility methods to be defined on fields which may be present. To define a schema for a document, create a class that inherits from :class:`~mongoengine.Document`. Fields are specified by adding **field objects** as class attributes to the document class:: from mongoengine import * import datetime class Page(Document): title = StringField(max_length=200, required=True) date_modified = DateTimeField(default=datetime.now) Fields ------ By default, fields are not required. To make a field mandatory, set the :attr:`required` keyword argument of a field to ``True``. Fields also may have validation constraints available (such as :attr:`max_length` in the example above). Fields may also take default values, which will be used if a value is not provided. Default values may optionally be a callable, which will be called to retrieve the value (such as in the above example). The field types available are as follows: * :class:`~mongoengine.StringField` * :class:`~mongoengine.IntField` * :class:`~mongoengine.FloatField` * :class:`~mongoengine.DateTimeField` * :class:`~mongoengine.ListField` * :class:`~mongoengine.ObjectIdField` * :class:`~mongoengine.EmbeddedDocumentField` * :class:`~mongoengine.ReferenceField` List fields ^^^^^^^^^^^ MongoDB allows the storage of lists of items. To add a list of items to a :class:`~mongoengine.Document`, use the :class:`~mongoengine.ListField` field type. :class:`~mongoengine.ListField` takes another field object as its first argument, which specifies which type elements may be stored within the list:: class Page(Document): tags = ListField(StringField(max_length=50)) Embedded documents ^^^^^^^^^^^^^^^^^^ MongoDB has the ability to embed documents within other documents. Schemata may be defined for these embedded documents, just as they may be for regular documents. To create an embedded document, just define a document as usual, but inherit from :class:`~mongoengine.EmbeddedDocument` rather than :class:`~mongoengine.Document`:: class Comment(EmbeddedDocument): content = StringField() To embed the document within another document, use the :class:`~mongoengine.EmbeddedDocumentField` field type, providing the embedded document class as the first argument:: class Page(Document): comments = ListField(EmbeddedDocumentField(Comment)) comment1 = Comment('Good work!') comment2 = Comment('Nice article!') page = Page(comments=[comment1, comment2]) Reference fields ^^^^^^^^^^^^^^^^ References may be stored to other documents in the database using the :class:`~mongoengine.ReferenceField`. Pass in another document class as the first argument to the constructor, then simply assign document objects to the field:: class User(Document): name = StringField() class Page(Document): content = StringField() author = ReferenceField(User) john = User(name="John Smith") john.save() post = Page(content="Test Page") post.author = john post.save() The :class:`User` object is automatically turned into a reference behind the scenes, and dereferenced when the :class:`Page` object is retrieved. Document collections -------------------- Document classes that inherit **directly** from :class:`~mongoengine.Document` will have their own **collection** in the database. The name of the collection is by default the name of the class, coverted to lowercase (so in the example above, the collection would be called `page`). If you need to change the name of the collection (e.g. to use MongoEngine with an existing database), then create a class dictionary attribute called :attr:`meta` on your document, and set :attr:`collection` to the name of the collection that you want your document class to use:: class Page(Document): title = StringField(max_length=200, required=True) meta = {'collection': 'cmsPage'} Document inheritance -------------------- To create a specialised type of a :class:`~mongoengine.Document` you have defined, you may subclass it and add any extra fields or methods you may need. As this is new class is not a direct subclass of :class:`~mongoengine.Document`, it will not be stored in its own collection; it will use the same collection as its superclass uses. This allows for more convenient and efficient retrieval of related documents:: # Stored in a collection named 'page' class Page(Document): title = StringField(max_length=200, required=True) # Also stored in the collection named 'page' class DatedPage(Page): date = DateTimeField() Working with existing data ^^^^^^^^^^^^^^^^^^^^^^^^^^ To enable correct retrieval of documents involved in this kind of heirarchy, two extra attributes are stored on each document in the database: :attr:`_cls` and :attr:`_types`. These are hidden from the user through the MongoEngine interface, but may not be present if you are trying to use MongoEngine with an existing database. For this reason, you may disable this inheritance mechansim, removing the dependency of :attr:`_cls` and :attr:`_types`, enabling you to work with existing databases. To disable inheritance on a document class, set :attr:`allow_inheritance` to ``False`` in the :attr:`meta` dictionary:: # Will work with data in an existing collection named 'cmsPage' class Page(Document): title = StringField(max_length=200, required=True) meta = { 'collection': 'cmsPage', 'allow_inheritance': False, } Documents instances =================== To create a new document object, create an instance of the relevant document class, providing values for its fields as its constructor keyword arguments. You may provide values for any of the fields on the document, but only **required** fields are necessary at this stage:: >>> page = Page(title="Test Page") >>> page.title 'Test Page' You may also assign values to the document's fields using standard object attribute syntax:: >>> page.title = "Example Page" >>> page.title 'Example Page' Saving and deleting documents ----------------------------- To save the document to the database, call the :meth:`~mongoengine.Document.save` method. If the document does not exist in the database, it will be created. If it does already exist, it will be updated. To delete a document, call the :meth:`~mongoengine.Document.delete` method. Note that this will only work if the document exists in the database and has a valide :attr:`id`. Document IDs ------------ Each document in the database has a unique id. This may be accessed through the :attr:`id` attribute on :class:`~mongoengine.Document` objects. Usually, the id will be generated automatically by the database server when the object is save, meaning that you may only access the :attr:`id` field once a document has been saved:: >>> page = Page(title="Test Page") >>> page.id >>> page.save() >>> page.id ObjectId('123456789abcdef000000000') Alternatively, you may explicitly set the :attr:`id` before you save the document, but the id must be a valid PyMongo :class:`ObjectId`. Querying the database ===================== :class:`~mongoengine.Document` classes have an :attr:`objects` attribute, which is used for accessing the objects in the database associated with the class. The :attr:`objects` attribute is actually a :class:`~mongoengine.queryset.QuerySetManager`, which creates and returns a new a new :class:`~mongoengine.queryset.QuerySet` object on access. The :class:`~mongoengine.queryset.QuerySet` object may may be iterated over to fetch documents from the database:: # Prints out the names of all the users in the database for user in User.objects: print user.name Filtering queries ----------------- The query may be filtered by calling the :class:`~mongoengine.queryset.QuerySet` object with field lookup keyword arguments. The keys in the keyword arguments correspond to fields on the :class:`~mongoengine.Document` you are querying:: # This will return a QuerySet that will only iterate over users whose # 'country' field is set to 'uk' uk_users = User.objects(country='uk') Fields on embedded documents may also be referred to using field lookup syntax by using a double-underscore in place of the dot in object attribute access syntax:: # This will return a QuerySet that will only iterate over pages that have # been written by a user whose 'country' field is set to 'uk' uk_pages = Page.objects(author__country='uk') Querying lists ^^^^^^^^^^^^^^ On most fields, this syntax will look up documents where the field specified matches the given value exactly, but when the field refers to a :class:`~mongoengine.ListField`, a single item may be provided, in which case lists that contain that item will be matched:: class Page(Document): tags = ListField(StringField()) # This will match all pages that have the word 'coding' as an item in the # 'tags' list Page.objects(tags='coding') Query operators --------------- Operators other than equality may also be used in queries; just attach the operator name to a key with a double-underscore:: # Only find users whose age is 18 or less young_users = Users.objects(age__lte=18) Available operators are as follows: * ``neq`` -- not equal to * ``lt`` -- less than * ``lte`` -- less than or equal to * ``gt`` -- greater than * ``gte`` -- greater than or equal to * ``in`` -- value is in list (a list of values should be provided) * ``nin`` -- value is not in list (a list of values should be provided) * ``mod`` -- ``value % x == y``, where ``x`` and ``y`` are two provided values * ``all`` -- every item in array is in list of values provided * ``size`` -- the size of the array is * ``exists`` -- value for field exists Limiting and skipping results ----------------------------- Just as with traditional ORMs, you may limit the number of results returned, or skip a number or results in you query. :meth:`~mongoengine.queryset.QuerySet.limit` and :meth:`~mongoengine.queryset.QuerySet.skip` and methods are available on :class:`~mongoengine.queryset.QuerySet` objects, but the prefered syntax for achieving this is using array-slicing syntax:: # Only the first 5 people users = User.objects[:5] # All except for the first 5 people users = User.objects[5:] # 5 users, starting from the 10th user found users = User.objects[10:15] Aggregation ----------- MongoDB provides some aggregation methods out of the box, but there are not as many as you typically get with an RDBMS. MongoEngine provides a wrapper around the built-in methods and provides some of its own, which are implemented as Javascript code that is executed on the database server. Counting results ^^^^^^^^^^^^^^^^ Just as with limiting and skipping results, there is a method on :class:`~mongoengine.queryset.QuerySet` objects -- :meth:`~mongoengine.queryset.QuerySet.count`, but there is also a more Pythonic way of achieving this:: num_users = len(User.objects) Further aggregation ^^^^^^^^^^^^^^^^^^^ You may sum over the values of a specific field on documents using :meth:`~mongoengine.queryset.QuerySet.sum`:: yearly_expense = Employee.objects.sum('salary') .. note:: If the field isn't present on a document, that document will be ignored from the sum. To get the average (mean) of a field on a collection of documents, use :meth:`~mongoengine.queryset.QuerySet.average`:: mean_age = User.objects.average('age') As MongoDB provides native lists, MongoEngine provides a helper method to get a dictionary of the frequencies of items in lists across an entire collection -- :meth:`~mongoengine.queryset.QuerySet.item_frequencies`. An example of its use would be generating "tag-clouds":: class Article(Document): tag = ListField(StringField()) # After adding some tagged articles... tag_freqs = Article.objects.item_frequencies('tag', normalize=True) from operator import itemgetter top_tags = sorted(tag_freqs.items(), key=itemgetter(1), reverse=True)[:10]