Tastypie Norel、django、mongodb:筑巢太多

Tastypie Norel、django、mongodb:筑巢太多,django,mongodb,backbone.js,tastypie,django-mongodb-engine,Django,Mongodb,Backbone.js,Tastypie,Django Mongodb Engine,我正在用django、backbone.js、tastypie和mongodb开发一个web应用程序。为了使tastypie和django适应mongodb,我使用了django mongodb引擎和tastypie Norel。此应用程序有一个模型项目,其中有一个任务列表。看起来是这样的: class Project(models.Model): user = models.ForeignKey(User) tasks = ListField(Embedded

我正在用django、backbone.js、tastypie和mongodb开发一个web应用程序。为了使tastypie和django适应mongodb,我使用了django mongodb引擎和tastypie Norel。此应用程序有一个模型项目,其中有一个任务列表。看起来是这样的:

   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)
多亏了tastypie nonrel,通过/api/v1/project/:id:/tasks/上的GET请求,可以以一种简单的方式获取项目的任务列表

现在,我想用注释列表扩展此任务模型:

   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)
此实现的问题在于,tastypie nonrel不支持另一个嵌套,因此无法简单地将注释发布到/api/v1/project/:id:/task/:id:/comments/

另一种方法是只向/api/v1/project/:id:/Task/发出任务的PUT请求,但如果两个用户决定同时向同一任务添加注释,则会产生问题,因为最后一次PUT将覆盖上一次PUT

最后一个选项(除了更改tastypie nonrel)是不在任务中嵌入注释,而只保留ForeignKey,因此请求将转到/api/v1/Comment/。我的问题是,这是否破坏了使用MongoDB的好处(因为需要交叉查询)?有没有更好的办法


我对栈中的任何技术都没有什么经验,所以可能是我没有很好地关注这个问题。欢迎您提出任何建议。

看来您的嵌套太多了。也就是说,您可以为tastypie创建自定义方法/URL映射,然后运行自己的逻辑,而不是依赖“自动魔术”tastypie。如果您担心注释覆盖问题,您仍然需要事务。然后,您的代码应该足够健壮,能够处理失败事务的行为,例如重试。如果你经常锁定一个有很多编写器的大对象,那么这肯定会极大地限制你的写操作,这也指向了一个设计问题

您可以稍微缓解这种情况的一种方法是写入中间源,如任务队列或redis,然后根据需要转储注释。这取决于您的解决方案的可靠性/持久性。任务队列将至少处理失败事务的重试;有了redis,你可以用pub/sub做点什么

你应该考虑一下关于IMOGDB的设计IMO的一些事情。

  • 避免创建过大的单片对象。虽然这是Mongo的一个优点,但这取决于您的使用情况。例如,如果您总是将项目作为顶级对象返回,那么随着任务和注释的增加,仅网络流量就会降低性能

    想象一个非常做作的例子,其中项目是特定的 数据是10k,每个任务单独是5k,每个评论单独是2k,如果你有一个项目有5个任务,每个任务10个评论,你说的是10k+5*5k+10*2k。对于一个有很多评论的非常活跃的项目,这将是通过网络发送的沉重负担。您可以执行切片/投影查询来协调此问题,但有一些限制和含义

  • 根据上面的推论,根据您的用例构造您的对象。如果你不需要把东西放在一起,它们可以放在不同的收藏中。仅仅因为您“认为”需要将它们重新组合在一起,并不意味着在实现方面需要在同一个获取中检索它们(尽管这通常是理想的)

    即使您确实需要一个用例/屏幕中的所有内容,在某些设计中可能的另一个解决方案是使用AJAX并行加载,甚至在页面加载后通过JavaScript延迟加载。例如,您可以在顶部加载任务信息,然后进行异步调用以分别加载注释,类似于disqs或Livefyre在其他站点中作为集成的方式。这有助于在某种程度上解决嵌套问题,因为您可以摆脱任务/项目级别,只需在每个注释/记录上存储一些ID,就可以在集合之间进行查询

  • 请记住,您可能不希望一次检索所有注释,如果您有很多注释,您可能会遇到一个文档大小的限制。在Mongo的最新版本中,数据量越来越大,但是,返回到上面的第一项,拥有一条包含大量数据的记录通常是没有意义的

我的建议是:

  • 如果您担心评论丢失,请使用事务

  • 如果您担心由于#1而导致写入竞争和丢失内容,请添加一个任务队列/redis/一些持久的东西。如果没有,忽略它。如果你失去了一条评论,这是世界末日吗

  • 考虑将注释重组为单独的集合,以缓解您的Tastype问题。如果需要,加载延迟或并行的内容


  • 看起来,如果您想要这么多嵌套模型,mongodb可能不是最好的存储解决方案——为什么不使用基于sql的数据库呢?是的,可以。这是一个项目,只是为了了解MongoDB,但尽管它有一些很酷的东西,但在我看来,一旦你做了一些不平凡的事情,开发就会变得很复杂。