Spring Data MongoDB - 嵌入式文档作为其他文档的参考

时间:2016-07-01 19:03:29

标签: spring mongodb spring-data spring-data-mongodb

我想知道在其他文档中使用嵌入式文档作为参考是否可能(甚至是正确的)。

我知道我可以将嵌入式文档移动到自己的集合中,但主要目标是获得嵌入式文档的性能优势并避免重复。

例如:

用户

{
    _id: ObjectId("4fed0591d17011868cf9c982"),
    _class: "User"
    ...
    addresses: [ {
        _id: ObjectId("87KJbk87gjgjjygREewakj86"),
        _class: "Address",
        ...
    } ]
}

顺序

{
    _id: ObjectId("gdh60591d123487658cf9c982"),
    _class: "Order",
    ...
    address: ObjectId("87KJbk87gjgjjygREewakj86")
}

3 个答案:

答案 0 :(得分:6)

您的案例让我想起了典型的关系方法,当我开始使用面向文档的数据库时,我也是它的受害者。您所有的 引用了示例中的实体,不再存在冗余。

你应该开始习惯放开规范化并开始复制数据的想法。在许多情况下,很难确定应该引用哪些数据以及应该嵌入哪些数据。不过,你的情况往往很清楚。

在不知道整个域模型的情况下,地址似乎是值对象的完美候选者。不要维护Address集合,将其嵌入用户对象中。在Order中,您可以对用户进行引用,这可以隐式地为您提供地址对象,并且可能有意义,因为订单是由用户创建的。

但是......我建议您将地址完全嵌入订单中。首先,它更快,因为您不需要解析引用。其次,发货订单中的地址永远不会改变!考虑去年的订单。如果你持有对地址的引用,一旦用户更改了地址,你就会丢失它们发送到哪个地址的信息。

建议:始终拍摄地址的快照并将其嵌入Order。将用户的MongoDB ID保存为`Order中的常规字符串(无@DBRef)。如果用户应更改其地址,您可以查询该用户的所有未发货订单并修改该地址。

答案 1 :(得分:1)

既然你问这是否正确,我会轻轻地说,“不。”至少不是典型的。

但如果你确实想坚持使用用户的嵌入地址:

您可以在Order对象中引用用户嵌入的地址,而不是您想象的方式!如果您按顺序存储了用户的id(如果Order belongs_to User,它应该已存在),那么您只需使用user.address而不是像您一样复制地址实例。

<强> ALTERNATIVE

我希望能够说明一种更好的域建模方法......

更常见的方法是使用用户的地址作为订单的默认“送货地址”来实例化新订单对象,但如果需要,允许用户覆盖送货地址。从理论上讲,每个订单都可以有不同“发货到”地址。

仅仅因为两个类都有一个地址,并不意味着它们必须是同一个地址。

<强>评注

订单更像是历史文件,而不是更改的文件。因此,订单通常是 immutable 一旦放置,您的模型允许每次用户更改其地址时更改地址。这种变化会影响到订单,并且在正常订单业务逻辑发生的情况下会不正确。

假设您去年在西班牙的地址,并且您在去年运行订单报告时显示西班牙订单#1。想象一下,如果你今年的地址现在是葡萄牙,那么#1号订单现在会在同一份报告中显示葡萄牙。这实际上是不正确的。

顺便说一句:@Matt给了你一个提示,从“问题领域”的角度来看,你可能不想像你一样对它进行建模。我只是在详细说明......

答案 2 :(得分:0)

由于我没有回答,我会在这里发布我是如何做到的。如果你有更好的解决方案,我很高兴在这里。

看起来没有办法在另一个集合中创建/引用集合,所以我不得不将用户集合中的地址提取到它自己的集合中,并在提及的用户和订单集合中创建一个引用{{3} }。我期待更灵活的东西,但找不到。

用户

{
    _id: ObjectId("4fed0591d17011868cf9c982"),
    _class: "User"
    ...
    addresses: [ {
        "$ref" : "addresses",
        "$id" : ObjectId("87KJbk87gjgjjygREewakj86")
    } ]
}

<强>地址

{
    _id: ObjectId("87KJbk87gjgjjygREewakj86"),
    ...
}

<强>顺序

{
    _id: ObjectId("gdh60591d123487658cf9c9867"),
    _class: "Order",
    ...
    address: {
        "$ref" : "addresses",
        "$id" : ObjectId("87KJbk87gjgjjygREewakj86")
    }
}