2

假设有两个单独的集合: Cities{name: "NYC", area: "1223", people: [1,2,3]} 和 Person {personId:1, name:"abc"}

如您所见,我们在城市中关联了人员的 ID(RDBMS 中的一种外键)。

现在,如果我决定删除 Id = 1 的人,那么我想更新 Cities 中的 people 数组,就像 RDBMS 中的级联删除操作一样,我知道我们没有按照this的级联删除类型的操作,并且我们在 MOngoDB 中没有事务,如果我们以某种方式未能对城市执行“级联删除”类型的操作,那么数据库可能会处于不一致状态。如何确保整个“删除人+城市级联删除”作为MongoDB中的原子操作?如果不能,那么我们是否更喜欢嵌入而不是链接?

4

3 回答 3

3

在操作速度和一致性方面,嵌入优于链接。您要实现的是 mongodb 中的事务操作,它不是原子的,因为它涉及多个文档。

您可以很容易地从每个人员文档中引用城市,而不是让每个城市引用每个人。对于您所拥有的这种多对一关系,它是一种更健全的结构。

如果在类似情况下数据一致性对您的应用程序很重要,您可能需要考虑使用mongodb 的模拟 RDBMS 事务的两阶段提交模式。

于 2013-02-06T14:10:24.573 回答
1

如何确保整个“删除人+城市级联删除”作为MongoDB中的原子操作?

正如其他人所说,MongoDB 有一个两阶段提交的客户端版本,但是:

  • 不提供两阶段事务提交
  • 不是原子的
  • 有相当大的开销
  • 是客户端(实际上拒绝了您从服务器端获得的任何好处,即失败)
  • 并且在发生故障时无法提供信息和交易的安全性

话虽如此,如果您可以依靠您的应用程序写入数据库并且不会失败,那么两阶段提交的 MongoDB 版本可以在这里工作;但是,那么为什么您不只是一个接一个地执行一个查询,而不是增加使用假两阶段提交的额外开销。

通常,假设如果其中一个删除查询成功则可以写入 mongodb,但是如果它们没有将级联的父行“标记”为已删除或其他东西,并且有一个专用的 cronjob 稍后会返回并且以一致的方式清理它(因为在那里这样做会延迟客户端)。

至于哪种模式设计最好,嵌入是首选是不正确的。我注意到你说:

然后我想更新 Cities 中的 people 数组

这很可能需要$pull在该阵列上使用 a 或类似的东西。我应该注意,如果该数组显着增长,那么内存中的操作$pull将比查询两个单独的集合要慢一些。

归根结底,我们无法就您的架构设计提供真正的建议,因为我们知道的不够多,所以我就这样吧。

编辑

尽管其他两个答案都有意义。如果您将 嵌入city_id到个人文档中,您实际上可以在一次调用中级联关系。当然,这是一个奇怪的问题,通常您可能有太多的子记录无法放入 Mongo 文档中,但这种情况适合。

于 2013-02-06T14:34:53.290 回答
0

您的架构设计应该与您的数据访问模式相匹配。因此,最好在 people 集合中包含一个 'city:NYC' 键:值对,而不是在 Cities 集合中包含 personID,因为如果您对 NYC 中的每个人都有一个 id,您可能会超过施加的 16mb 文档大小限制在 Mongodb 文档上,即因为数组将包含数百万个元素。

这将更容易更新一个人的城市(因为它发生的频率较低),而不是更新一个一直在变化的城市中的人数。管理多个更新的最安全方法可能是通过您的应用程序代码。

于 2013-02-06T14:03:52.940 回答