When you describe your MongoDocument, you can add some information about the relations beetween your objects. This will let you have a simple api to query all related objects from document.
Let’s create a blog post object :
>>> class BlogPost(MongoDocument):
... db_name = "test"
... collection_name = "mongokit"
... structure = {
... "blog_post":{
... "blog_id":unicode,
... "content":unicode,
... },
... }
now, let’s create the blog object.
>>> class Blog(MongoDocument):
... db_name = "test"
... collection_name = "mongokit"
... structure = {
... "blog":{"title":unicode}
... }
... related_to = {
... 'blog_posts':{'class':BlogPost, 'target':'blog_post.blog_id'},
... }
The related_to descriptor will tell MongoKit that we want to be able to get all blog post from a blog object. The syntax is :
- related_to = {
- ‘name_of_the_relation’:{
- ‘class’:RelatedClassObject, ‘target’: ‘field_where_the_id_is’,
}
For instance, let’s create a blog and some blog post:
>>> blog = Blog()
>>> blog['_id'] = u'my blog'
>>> blog['title'] = u'My Blog'
>>> blog.save()
>>> blog.related
>>> blog_post1 = BlogPost()
>>> blog_post1['_id'] = 1
>>> blog_post1['blog_post']['blog_id'] = blog['_id']
>>> blog_post1['blog_post']['content'] = u'a great blog post'
>>> blog_post1.save()
>>> blog_post2 = BlogPost()
>>> blog_post2['_id'] = 2
>>> blog_post2['blog_post']['blog_id'] = blog['_id']
>>> blog_post2['blog_post']['content'] = u'another great blog post'
>>> blog_post2.save()
Now, we want all blog post related to blog:
>>> blog_posts = blog.related.blog_posts()
>>> list(blog_posts)
[{u'blog_post': {u'content': u'a great blog post', u'blog_id': u'my blog'}, u'_id': 1}, {u'blog_post': {u'content': u'another great blog post', u'blog_id': u'my blog'}, u'_id': 2}]
You can filter all the related document by passing a query to the relation:
>>> blog_posts = blog.related.blog_posts({'blog_post.content':'a great blog post'})
>>> list(blog_posts)
[{u'blog_post': {u'content': u'a great blog post', u'blog_id': u'my blog'}, u'_id': 1}]
The MongoDocument.related property can handle many relations.
Let’s create another object related to our Blog object:
>>> class Author(MongoDocument):
... db_name = 'test'
... collection_name = 'mongokit'
... structure = {
... 'author':{
... 'name':unicode,
... 'blog_id':unicode,
... },
... }
The related property is set at MongoDocument‘s __init__ so we can update the Blog.related_to to handle Author object:
>>> Blog.related_to.update({'authors':{'class':Author, 'target':'author.blog_id'}})
let’s create another blog:
>>> blog = Blog()
>>> author1 = Author()
>>> author1['_id'] = u'me'
>>> author1['author']['name'] = u'Me'
>>> author1['author']['blog_id'] = blog['_id']
>>> author1.save()
>>> author2 = Author()
>>> author2['_id'] = u'you'
>>> author2['author']['name'] = u'You'
>>> author2['author']['blog_id'] = blog['_id']
>>> author2.save()
Now let’s get our blog (remember, it must get another instaciation to update the related_to property) :
>>> blog = Blog.get_from_id('my blog')
blog has now two relations attached to the related property
>>> authors =blog.related.authors()
>>> list(authors)
[{u'_id': u'me', u'author': {u'blog_id': u'my blog', u'name': u'Me'}}, {u'_id': u'you', u'author': {u'blog_id': u'my blog', u'name': u'You'}}]
>>> blog_posts = list(blog.related.blog_posts())
>>> list(blog_posts)
[{u'blog_post': {u'content': u'a great blog post', u'blog_id': u'my blog'}, u'_id': 1}, {u'blog_post': {u'content': u'another great blog post', u'blog_id': u'my blog'}, u'_id': 2}]
Relations can handle autoref documents. This brings a full featured relational layer to MongoKit.
let’s create a Blog:
>>> class Blog(MongoDocument):
... db_name = "test"
... collection_name = "mongokit"
... structure = {
... "blog":{"title":unicode}
... }
and a BlogPost object:
>>> class BlogPost(MongoDocument):
... db_name = "test"
... collection_name = "mongokit"
... structure = {
... "blog_post":{
... "blog":Blog,
... "content":unicode,
... },
... }
... use_autorefs = True
BlogPost is declared after Blog so we have to fill related_to after BlogPost declaration
>>> Blog.related_to = {
... 'blog_posts':{'class':BlogPost, 'target':'blog_post.blog', 'autoref':True}
... }
>>> blog = Blog()
>>> blog['_id'] = u'my blog'
>>> blog['title'] = u'My Blog'
>>> blog.save()
>>> blog_post1 = BlogPost()
>>> blog_post1['_id'] = 1
we pass now the entired blog object:
>>> blog_post1['blog_post']['blog'] = blog
>>> blog_post1['blog_post']['content'] = u'a great blog post'
>>> blog_post1.save()
>>> blog_post2 = BlogPost()
>>> blog_post2['_id'] = 2
>>> blog_post2['blog_post']['blog'] = blog
>>> blog_post2['blog_post']['content'] = u'another great blog post'
>>> blog_post2.save()
Retrive relations is the same:
>>> blog_posts = list(blog.related.blog_posts())
[{u'blog_post': {u'blog': {u'blog': {u'title': None}, u'_id': u'my blog', u'title': u'My Blog'}, u'content': u'a great blog post'}, u'_id': 1}, {u'blog_post': {u'blog': {u'blog': {u'title': None}, u'_id': u'my blog', u'title': u'My Blog'}, u'content': u'another great blog post'}, u'_id': 2}]
Some time, structures is complexe and we need to describes the relation deeply. lambda is use to do this.
>>> class Article(MongoDocument):
... db_name = 'test'
... collection_name = 'mongokit'
... structure = {
... 'article': {
... 'title':unicode,
... 'tags':{unicode:int},
... }
... }
>>> class Tag(MongoDocument):
... db_name = 'test'
... collection_name = 'mongokit'
... structure = {
... 'tag':{
... 'title':unicode,
... }
... }
... related_to = {'articles':{'class':Article, 'target':lambda x:{'article.tags.%s' % x:{'$gt':1}}}}
the ‘target’ must be a string or a lambda expression. The lambda expression takes a parameter wich represent the object ‘_id’. In this example, the results of the lambda expression with the tag ‘foo’ will be :
{‘article.tags.foo’:{‘$gt’:1}}
this mean that only articles which have the tag ‘foo’ > 1 will be returned.
Now, let’s create some tags :
>>> foo = Tag()
>>> foo['_id'] = u'foo'
>>> foo['tag']['title'] = u'Foo'
>>> foo.save()
>>> bar = Tag()
>>> bar['_id'] = u'bar'
>>> bar['tag']['title'] = u'Bar'
>>> bar.save()
Let’s associate those tags with articles :
>>> article1 = Article()
>>> article1['_id'] = u'article1'
>>> article1['article']['title'] = u'First article'
>>> article1['article']['tags'][u'foo'] = 2
>>> article1['article']['tags'][u'bar'] = 3
>>> article1.save()
>>> article2 = Article()
>>> article2['_id'] = u'article2'
>>> article2['article']['title'] = u'Second article'
>>> article2['article']['tags'][u'foo'] = 0
>>> article2['article']['tags'][u'bar'] = 2
>>> article2.save()
we want all articles which have the tag ‘bar’ > 1:
>>> articles = bar.related.articles()
>>> list(articles)
[{u'article': {u'tags': {u'foo': 2, u'bar': 3}, u'title': u'First article'}, u'_id': u'article1'}, {u'article': {u'tags': {u'foo': 0, u'bar': 2}, u'title': u'Second article'}, u'_id': u'article2'}]
idem with the tag ‘foo’:
>>> articles = foo.related.articles()
>>> list(articles)
[{u'article': {u'tags': {u'foo': 2, u'bar': 3}, u'title': u'First article'}, u'_id': u'article1'}]