MongoDB一对多关系

时间:2014-08-25 12:23:47

标签: mongodb

我开始学习MongoDB和我在某一刻我问自己如何解决MongoDB中的“一对多”关系设计。在搜索时,我在其他帖子/文章中发现了许多评论,例如“你在思考关系”。 好的我同意。在某些情况下,例如重复信息不会成为问题,例如CLIENTS-ORDERS示例。

但是,假设您有表:ORDERS,它具有嵌入式DETAIL结构,其中包含客户购买的PRODUCTS。 因此,对于一件或另一件事,您需要更改已嵌入多个订单中的产品名称(或其他类型的信息)。

最后,你很有可能在MongoDB中进行一对多的关系(这意味着,将ObjectID字段作为另一个集合的链接),这样你就可以解决这个简单的问题,不是吗? 但每当我发现一些关于此的文章/评论时,它都表示这将成为Mongo的性能缺陷。这有点令人失望

在MongoDB中是否存在另一种解决/设计这种没有性能故障的方法?

3 个答案:

答案 0 :(得分:11)

问题在于您过度规范化数据。订单由在给定时间点居住在某个地点的客户定义,在订单发生时支付一定的有效价格(可能在应用程序生命周期内发生重大变化,无论如何都要记录,以及几个其他参数仅在某个时间点有效。因此,对于文档订单(双关语),您需要保留该特定时间点的所有数据我来举个例子:

{ _id: "order123456789",
  date: ISODate("2014-08-01T16:25:00.141Z"),
  customer: ObjectId("53fb38f0040980c9960ee270"),
  items:[ ObjectId("53fb3940040980c9960ee271"),
          ObjectId("53fb3940040980c9960ee272"),
          ObjectId("53fb3940040980c9960ee273")
         ],
 Total:400
 }

现在,只要客户和商品的详细信息都没有变化,您就可以重现订单发送到的位置,订单价格和价格相同。但是现在如果客户改变了它的地址会发生什么?或者如果项目的价格发生变化?您需要在各自的文档中跟踪这些更改。它将 更容易且足够有效地存储订单,如:

{
  _id: "order987654321",
  date: ISODate("2014-08-01T16:25:00.141Z"),
  customer: {
               userID: ObjectId("53fb3940040980c9960ee283"),
               recipientName: "Foo Bar"
               address: {
                          street: "742 Evergreen Terrace",
                          city: "Springfield",
                          state: null
                         }
            },
  items: [
    {count:1, productId:ObjectId("53fb3940040980c9960ee300"), price: 42.00 },
    {count:3, productId:ObjectId("53fb3940040980c9960ee301"), price: 0.99},
    {count:5, productId:ObjectId("53fb3940040980c9960ee302"), price: 199.00}
  ]
}

使用此数据模型和聚合管道的使用,您有以下几个优点:

  1. 您不需要独立跟踪客户的价格和地址或命名变更或礼品购买 - 它已经记录在案。
  2. 使用汇总管道,您可以创建价格趋势,而无需单独存储定价数据。您只需将商品的当前价格存储在订单文档中。
  3. 即使是复杂的聚合,例如价格弹性,州/市等的营业额,也可以通过非常简单的聚合来完成。
  4. 一般来说,可以肯定地说,在面向文档的数据库中,未来可能发生变化的每个属性或字段以及这种变化都会产生不同的语义,应该存储在文档中。未来可能发生变化但未触及语义含义的所有内容(示例中的用户密码)可以通过GUID链接。

答案 1 :(得分:9)

一对多关系

在这种关系中,有许多实体或许多实体映射到一个实体。例如。:   - 一个城市有很多人住在那个城市。说NYC有800万人。

我们假设以下数据模型:

 
  //city
  {
  _id: 1,
  name: 'NYC',
  area: 30,
  people: [{
      _id: 1,
      name: 'name',
      gender: 'gender'
        .....
    },
    ....
    8 million people data inside this array
    ....
  ]
}

这不会起作用,因为那将是非常巨大的。让我们试着翻一读。


 //people
 {
 _id: 1,
 name: 'John Doe',
 gender: gender,
 city: {
     _id: 1,
     name: 'NYC',
     area: '30'
       .....
   }
}

现在这个设计的问题是,如果显然有很多人住在纽约市,那么我们已经为城市数据做了很多重复。

对这些数据进行建模的最佳方法可能是使用真正的链接


 //people
 {
 _id: 1,
 name: 'John Doe',
 gender: gender,
 city: 'NYC'
}

//city
{
_id: 'NYC',
...
}

在这种情况下,people集合可以链接到city集合。知道我们没有外键约束,我们必须保持一致。所以,这是一对多关系。它需要2个收藏。对于小到少(也是一对多),像博客评论的关系。评论可以作为数组嵌入帖子文档中。

因此,如果它真的是一对多,那么2个集合最适合链接。但是对于一个人来说,一个单一的集合通常就足够了。

答案 2 :(得分:0)

所以我赞美@BaptisteL来澄清我对MongoDB的假设 “不要忘记mongodb是一个NoSQL数据库,所以如果你在你的数据库中有很多这样的关系,那么你应该选择一个SQL数据库,因为mongodb在这方面总是不那么预先形成。” http://www.sarahmei.com/blog/2013/11/11/why-you-should-never-use-mongodb/