32

假设以下“模式/关系”设计,使用级联删除操作处理删除的推荐做法是什么?

关系模式:

  +---------+ +--------+
  | 学生|-*--------1-[注册]-1--------*-| 课程 |
  +---------+ +--------+

MongoDB:

  +---------+ +--------+
  | 学生|-*----------------*-| 课程 |
  +---------+ +--------+

考虑到学生注册课程的这种经典设计,在使用 MongoDB 时,在学生中包含课程集合(反之亦然)似乎是一个合适的数据模型(这对于关系/注册表来说没有任何意义)。但是来自关系世界的我应该如何处理删除课程的语义?也就是说,当一个课程被删除时,所有的“注册”记录也应该被删除。也就是说,我应该从每个学生记录的集合中删除课程。看起来我必须触发 2 个查询:一个用于删除课程,然后从每个学生的收藏中删除它。有没有办法让一个查询来执行这种“级联删除”之类的语义而无需额外的查询?数据模型需要改变吗?

注意:对于所有其他用例,上述数据模型工作得很好:

  • 删除学生=>只需删除该学生以及随之删除的相关课程集合。
  • 愿意放弃课程=>的学生只需将其从学生课程集中删除即可
  • 添加学生/课程=>本质上只是将其添加到相应的“表”中。

唯一棘手的事情是处理课程的删除。我应该如何在 MongoDB 中处理这种情况,因为我来自关系背景并且无法弄清楚这一点。

4

2 回答 2

17

你正在做的是在 Mongo 中最好和最优化的方法。我处于类似的情况,在尝试了 N:M 设计模式的所有可能实现之后,也得出了相同的解决方案。

显然,这不是 mongodb 的东西,而更像是一个 NoSQL 的概念,其中,变化较少的数据(Courses)可以单独保存。而且由于删除课程不会是一个非常频繁的操作,因此它足以通过所有记录来删除它。

另一方面,你可以让它保持原样。在您的应用程序逻辑中,只需忽略 Student 文档中的 Courses 值,这些值在 Course 文档中根本没有 reference_id。但在这种情况下,您必须确保旧的已删除 Course_id 未被重用。

或者只使用课程文档上的已删除标志并处理应用程序逻辑中的所有其他内容。

于 2015-02-06T09:17:19.820 回答
5

我将根据 Mongo 团队的建议进行回答。我也来自关系数据库,在开始理解这些概念时遇到了一些问题。Mongo 团队建议使用“应用程序驱动”模式的思想进行设计,因此您必须首先弄清楚哪些数据块在一起。请记住,在 Mongo 中以任何可能的方式都没有这样的事务概念,即使我们发明了一个处理事务的驱动程序,我们也应该为此实现自己的解决方案。这意味着如果我有两个需要始终同时更新的业务对象并且我不能容忍此操作失败,我必须将它们加入到单个文档中(原子)。

在您的情况下,您有两个文档,学生和课程,以及两者之间的关系(一个学生注册 N 门课程)。我认为课程不需要一直更改,因此可以将它们存储在不同的集合中。但关键是它们之间的关系,在这种情况下,您需要自动删除一个学生及其注册的所有课程。因此,最合适的解决方案是将关系嵌入到学生中,并保留一个单独的课程集合。当您删除学生时,关系同时被删除:

学生杰森:

{ _id: ObjectId('...'), name:"John", lastname:"Smith", 
courses: [ 1, 100, 50, 67 ], ...
}

课程可以是它们之间的单独集合。这是在 Mongo 中处理它的方法。原子操作必须嵌入到单个文档中。我假设 Courses 是一个变化不大的课程列表,如果它们是由 Student 设计的,我们可以稍微改变一下解决方案。

于 2013-12-04T13:20:44.867 回答