4

我正在使用 django、backbone.js、tastepie 和 mongodb 开发一个 Web 应用程序。为了使tastepie和django适应mongodb,我使用了django-mongodb-engine和tastepie-nonrel。这个应用程序有一个模型项目,它有一个任务列表。所以它看起来像这样:

   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)

感谢tastepie-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)

这个实现的问题是tastepie-nonrel不支持另一个嵌套,所以不可能简单地向/api/v1/project/:id:/task/:id:/comments/发表评论

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

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

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

4

1 回答 1

1

看起来你嵌套太多了。也就是说,您可以为美味派创建自定义方法/URL 映射,然后运行自己的逻辑,而不是依赖“自动魔术”美味派。如果您担心评论覆盖问题,那么无论如何您都需要交易。然后,您的代码应该足够健壮以处理失败事务的行为,例如重试。如果您经常锁定一个有许多写入器的大型对象,这肯定会大大限制您的写入,但是,这也指向一个设计问题。

可以稍微缓解这种情况的一种方法是写入中间源,例如任务队列或 redis,然后根据需要转储到注释中。这仅取决于您的解决方案的可靠性/耐用性。任务队列至少会处理失败事务的重试;使用 redis,您可以使用 pub/sub 做一些事情。

您应该考虑有关 MongoDB 的设计 IMO 的一些事项。

  • 避免创建过大的整体对象。虽然这是 Mongo 的一个好处,但这取决于你的使用情况。例如,如果您总是将项目作为顶级对象返回,那么随着任务和评论的增长,仅网络流量就会影响性能。

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

  • 上述的推论,根据您的用例构建您的对象。如果您不需要将东西重新组合在一起,它们可以位于不同的集合中。仅仅因为您“认为”您需要将它们重新组合在一起,并不意味着它们需要在同一个提取中检索(尽管这通常是理想的)。

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

  • 请记住,您可能不想一次检索所有评论,如果您有很多评论,您可能会遇到一个文档大小的限制。在最近的 Mongo 版本中,现在的大小更大了,但是无论如何,拥有一条包含大量数据的记录通常是没有意义的,回到上面的第一项。

我的建议是:

  1. 如果您担心丢失评论,请使用事务。

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

  3. 考虑将特别是评论重组到一个单独的集合中,以缓解您的美味问题。如果需要,加载延迟或并行的东西。

于 2014-03-17T10:10:40.470 回答