我正在使用 django、backbone.js、tastypie 和 mongodb 开发一个 web 应用程序。为了使tastypie 和django 适应mongodb,我使用django-mongodb-engine 和tastypie-nonrel。这个应用程序有一个模型 Project,它有一个任务列表。所以它看起来像这样:
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 请求以简单的方式获取项目的任务列表
现在我想用一个注释列表来扩展这个 Task 模型:
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 将覆盖前一个。
最后一个选项(除了改变tastypie-nonrel)是不要在任务中嵌入Comment而只保留ForeignKey,这样请求就会转到/api/v1/Comment/。我的问题是这是否会破坏使用 MongoDB 的好处(因为它需要交叉查询)?有没有更好的方法来做到这一点?
我对堆栈的任何技术几乎没有经验,所以可能是我没有很好地关注问题。欢迎任何建议。
最佳答案
看起来你嵌套太多了。也就是说,您可以为tastypie 创建自定义方法/URL 映射,然后运行您自己的逻辑,而不是依赖“自动魔术”tastypie。如果您担心评论覆盖问题,则无论如何都需要交易。然后,您的代码应该足够健壮以处理失败事务的行为,例如重试。如果您经常锁定具有许多作者的大对象,这肯定会大大限制您的写入,但是,这也指向设计问题。
您可以稍微缓解这种情况的一种方法是写入中间源,例如任务队列或 redis,然后根据需要转储到注释中。这仅取决于您的解决方案的可靠性/耐用性。任务队列至少会处理失败事务的重试;使用 redis,您可以使用 pub/sub 做一些事情。
关于 MongoDB 的 IMO 设计,您应该考虑一些事项。
想象一个非常人为的例子,其中项目特定于
数据是10k,单独每个任务5k,单独每个评论2k,如果你有一个项目有5个任务,每个任务10个评论,你说的是10k + 5*5k + 10*2k。对于一个有很多评论的非常活跃的项目,这将是通过网络发送的繁重。您可以执行切片/投影查询来解决这个问题,但有一些限制和影响。
即使您确实需要一个用例/屏幕中的所有内容,在某些设计中可能的另一种解决方案是使用 AJAX 并行加载内容,甚至在页面加载后通过 JavaScript 延迟加载。例如,您可以在顶部加载任务信息,然后进行异步调用以单独加载评论,类似于 Disqus 或 Livefyre 在其他站点中作为集成工作的方式。这可以在某种程度上帮助解决您的嵌套问题,因为您可以摆脱任务/项目级别,只需在每个评论/记录上存储一些 ID,以便能够在集合之间进行查询。
我的建议是: