【问题标题】:CQRS Read models in a NoSql (Mongo DB)NoSql (Mongodb) 中的 CQRS 读取模型
【发布时间】:2017-03-24 12:22:54
【问题描述】:

您好,这是我第一次使用 DDD/CQRS。我已经阅读了多种知识来源,但我仍然有点困惑,也许有人可以帮忙:)

让我们假设我们有产品和客户(可能不同的有界上下文)的简单情况。 客户可以购买一种产品,并且他想查看他购买的所有产品。

在这种情况下,我意识到我需要一个 UserPurchasesView 视图模型:

  • purchaseId(mongo 主键)
  • 用户ID,
  • 产品:{id, name, image, shortDescription, [也许是其他一些]}
  • 奖品
  • 时间戳

现在...问题是我的域正在产生类似 UserPurchasedProduct(userId, productId) 的事件。我可以用奖品、产品名称或其他东西来丰富活动,但不是所有领域。我已经到了丰富似乎是错误的地步。

在这一点上,我意识到我需要像 ProductDetailsView 这样的东西:

  • productId(主键)
  • 奖品
  • 姓名
  • 简短说明
  • 徽标

此视图由以下事件维护:ProductCreated、ProductRenamed、ProductImageChanged

现在我们有两个选择...

  1. 当 UserPurchasedProduct 事件出现时查看 ProductDetailsView,获取所有需要的产品详细信息并将其保存在 UserPurchasesView 中以便更快地读取。这个解决方案看起来还不错,但它引入了一些额外的耦合,在我看来,这些视图在需要时无法很好地缩放。此外,在从事件存储中回复所有事件时,两个视图必须一起重建(在这种情况下重建也更加棘手)。
  2. 仅保留 UserPurchasesView 中的 productId 并在用户查询其购买时读取多个视图。这是一些必须在某处完成的额外处理。在前端、后端控制器或某些读取模型高级 API 中。更新:我还意识到我还需要在 UserPurchasesView 中至少保留产品的奖品和名称(以防它发生变化),但有时您需要购买时的价值,有时您需要最近的价值.场景取决于业务,但我们可以同时想象。

这些解决方案对我来说都不完美。我错了,我错过了什么还是只是这样做的方式?谢谢!

【问题讨论】:

    标签: domain-driven-design cqrs


    【解决方案1】:

    你很好理解。

    因此,您必须在读取模型之间的耦合以及 UI 与单个读取模型之间的耦合之间做出选择。

    CQRS/ES 的主要优点之一是可以创建超快的读取模型(如果您愿意,可以查看视图),无需任何连接,完美的缓存,正如我所看到的那样。我个人每次都选择第一种方法,完全数据非规范化。视图非常快,模型非常干净清晰。 这是完美的解决方案,如果您想优化应用程序的读取端(我认为您应该这样做)。 通过监听正确的事件,您可以使这些读取模型与应用程序的其余部分保持同步。

    【讨论】:

      【解决方案2】:

      还有第三种选择:

      负责 UserPurchasesView 视图的投影不仅监听 UserPurchasedProduct 事件,还监听 ProductCreated、ProductRenamed、ProductImageChanged - 任何影响 UserPurchasesView 的产品相关事件。现在,除了它负责的读取模型的 UserPurchasesView 集合之外,它还需要一个私有集合来维护它感兴趣的产品位:({id, name, image, shortDescription, [也许是其他一些] }),这样当一个新的购买事件到来时,你就可以从某个地方获取这些产品字段的初始状态。由于您的 UserPurchasesView 无论如何都需要监听其中一些产品事件,以便在产品更改时保持最新状态,因此这并不是真正的额外工作,并且避免了对另一个投影 (ProductDetailsView) 的任何依赖。由于最终一致性,交叉投影依赖还存在潜在问题 - 如果在 UserPurchasedProduct 事件发生时产品甚至还没有出现在产品详细信息视图中怎么办?

      为避免任何并发问题,最简单的方法是让每个投影仅由单个进程和单个线程管理。这样,只要投影可以跨流按顺序接收事件(以便保证在产品购买之前看到产品创建),在产品存在之前看到购买就不会有问题。如果您在投影中引入分片或任何其他多线程,它会变得更加复杂。

      【讨论】:

      • 其实我是这么想的。在我的解决方案中,我有一个“投影”来监听购买和产品事件。但是这个单一进程投影维护了 2 个 mongo 集合 - UserPurchases 和 Products。它目前也为不同的 UI 视图维护了更多的集合,但是在需要时可以轻松地将其拆分为更多的投影。尽管如此,这两个集合必须始终关闭并一起维护(在使用商店中的所有事件重建投影期间也是如此)
      • 基本上这是第一个选项,但添加了更多细节。
      猜你喜欢
      • 1970-01-01
      • 2017-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-16
      • 1970-01-01
      • 2021-03-25
      • 1970-01-01
      相关资源
      最近更新 更多