djangomongodbbackbone.jstastypiedjango-mongodb-engine

Tastypie-nonrel, django, mongodb: too many nestings


I am developing a web application with django, backbone.js, tastypie and mongodb. In order to adapt tastypie and django to mongodb I am using django-mongodb-engine and tastypie-nonrel. This application has a model Project, which has a list of Tasks. So it looks like this:

   class Project(models.Model):
       user = models.ForeignKey(User)
       tasks = ListField(EmbeddedModelField('Task'), null=True, blank=True)

   class Task(models.Model):
       title = models.CharField(max_length=200)

Thanks to tastypie-nonrel, getting the list of task of a project is done in a simple way with a GET request at /api/v1/project/:id:/tasks/

Now I want to extend this Task model with a list of comments:

   class Task(models.Model):
       title = models.CharField(max_length=200)
       comments = ListField(EmbeddedModelField('Comment'), null=True, blank=True)

   class Comment(models.Model):
       text = models.CharField(max_length=1000)
       owner = models.ForeignKey(User)

The problem with this implementation is that tastypie-nonrel does not support another nesting, so is not possible to simple POST a comment to /api/v1/project/:id:/task/:id:/comments/

The alternative is to just make a PUT request of a Task to /api/v1/project/:id:/task/, but this would create problems if two users decide to add a comment to the same Task at the same time, as the last PUT would override the previous one.

The last option (aside from changing tastypie-nonrel) is to not embed Comment inside the Task and just hold the ForeignKey, so the request would go to /api/v1/Comment/. My question is if this breaks the benefits of using MongoDB (as it is needed cross queries)? Is there any better way of doing it?

I have little experience in any of the technologies of the stack, so it may be I am not focusing well the problem. Any suggestions are welcome.


Solution

  • It seems like you are nesting too much. That said, you can create custom methods/URL mappings for tastypie and then run your own logic instead of relying on "auto-magic" tastypie. If you are worried about the comment overriding issue, you need transactions anyway. Your code then should be robust enough to handle the behavior of a failed transaction, for example to retry. This would greatly throttle your writes for sure if you are constantly locking on a large object with many writers, however, which points to a design issue as well.

    One way you can mitigate this a bit is to write to intermediate source such as a task queue or redis, then dump in the comments as needed. It just depends on how reliable/durable your solution. A task queue would handle retries for failed transactions at least; with redis you can do something with pub/sub.

    You should consider a few things about your design IMO regarding MongoDB.

    My recommendations are:

    1. Use transactions if you're concerned about losing comments.

    2. Add a task queue/redis/something durable if you're worried about competing writes and losing things as a result of #1. If not, ignore it. Is it the end of the world if you lose a comment?

    3. Consider restructuring particularly comments into a separate collection to ease your tastypie issues. Load things deferred or in parallel if needed.