Harry Marr

Projects

About

Twitter

Recent Entries

Archive

Tag Cloud

RSS/Atom

Introducing MongoEngine

February 4th, 2010 — 9 Comments — Permalink

  • mongodb
  • mongoengine
  • nosql
  • python

MongoEngine is a Document-Object Mapper (think ORM, but for document databases) for working with MongoDB from Python. It uses a simple declarative API, similar to that of the Django ORM.

So what does it do?

Here's a brief run-down of some of the main features of MongoEngine:

  • Document schema declaration and validation
  • An elegant querying syntax, similar to that of Django
  • Document inheritance, with support for "polymorphic querying"
  • Aggregation methods, such as sum and average
  • Advanced query condition combination using Q objects
  • Session and authentication backends for Django

Show me the code!

To define a document, just inherit from the Document class and add some fields:

class BlogPost(Document):
    title = StringField(required=True)
    slug = StringField(required=True, max_length=250)
    content = StringField(required=True)
    date = DateTimeField(default=datetime.now, required=True)
    tags = ListField(StringField())

To save documents to the database, just instantiate a Document object, fill in the fields, and call save:

post = BlogPost(title='Introducing MongoEngine', slug='introducing-mongoengine')
post.content = 'MongoEngine is a Document-Object Mapper...'
post.tags = ['mongodb', 'mongoengine']
post.save()

To find documents, use the objects attribute of a Document subclass:

latest_posts = BlogPost.objects.order_by('-date')[:25]
mongodb_posts = BlogPost.objects(tags='mongodb')

How about a tag cloud? Simple:

# Get a dictionary with tags as the keys and frequencies as the values
tag_freqs = BlogPost.objects.item_frequencies('tag')

Every blog need comments, right?

class Comment(EmbeddedDocument):
    author = StringField()
    content = StringField(required=True)
    date = DateTimeField()

# Modify the previously defined BlogPost document
class BlogPost(Document):
    ...
    comments = ListField(EmbeddedDocumentField(Comment))
    ...

# Let's add a comment, this is performed as an atomic operation
comment = Comment(author=form['author'], content=form['content'])
BlogPost.objects(id=post_id).update(push__comments=comment)

I could go on, but I'll keep this post short and to the point. For more information, see the documentation. The source is available on GitHub, fork it and have a play!

Discussion

  • Thomas Wanschik 5 months, 3 weeks ago

    Hi, awesome work, really great! A friend of mine (Waldemar Kornewald) and i are working together on a non-relational port of Django. We already have a working backend for App Engine. It would be great to have a MongoDB backend for Django non-rel too. Are you interested in helping?

    Again really good work.

    Bye, Thomas

  • Mike Dirolf 5 months, 3 weeks ago

    This is a very cool Harry - looking forward to checking it out some more!

  • marc boeker 5 months, 3 weeks ago

    wow looks great. can't wait to check it out at the weekend. cheers marc

  • Pixy Misa 5 months, 3 weeks ago

    I have to say, that looks rather neat!

  • Harry Marr 5 months, 3 weeks ago

    Thomas: That sounds really interesting - are you planning on having a uniform API for all non-relational databases, or will different databases / database types (document, column, key-val, etc) have different APIs?

    Mike, Marc and Pixy: Cheers! I'll be posting more over the next few weeks on some of the more 'advanced' features, stay tuned!

  • Thomas Wanschik 5 months, 2 weeks ago

    Harry Marr: We plan to change Django in such a way that it supports non-relational databases without any changes to Django at a higher level at which the user formulates queries or defines his models. Until now we only changed minor things in Django itself (only a few lines of code) and chances are good that we do not need to change Django much more to support all non-relational databases. The rest is done by the non-relational database's backend (based on SQLCompiler introduced by the multi-db branch) itself. We already started to define a NonrelCompiler which provides functionality common to every non-relational database, thought it's located in djangoappengine because it's not complete enough yet.

    As a proof of concept we have started writing some django apps like nonrel search a full text search engine based on ListFields. This should work on MongoDB too as soon as a MongoDB backend exists for Django.

    At the moment it seems that we can get someone to work on a SimpleDB backend for Django and a MongoDB backend too. Maybe you can help on the MongoDB backend?

    I am looking forward to your next post :)

    Bye, Thomas

  • iapain 5 months, 2 weeks ago

    @Thomas It'd be nice "instead modifying django" you write a backend that supports django ORM actually its not very complicated there have been some tries in past but nothing like production ready.

  • Waldemar Kornewald 5 months ago

    @iapain: Actually, we do write backends. The problem is that some Django features require SQL, so we have to modify (clean up / refactor) Django in a few places. That's all.

  • Andy H. 3 months, 3 weeks ago

    So far works great, would love to see more activity on the mailing list and irc channel for when people need help, but so far I have been using Mongo Engine for a project and it works great.

Leave A Reply

You may use Markdown syntax but raw HTML will be escaped and headings normalised.

Log in

Mumblr is a basic Django tumblelog application that uses MongoDB with MongoEngine. Fork it on Github. Designed and developed by Harry Marr and Steve Challis.