MongoDB一对多关系

tap*_*tio 14 mongodb

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

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

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

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

Mar*_*erg 13

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

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

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

{
  _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}
  ]
}
Run Code Online (Sandbox Code Playgroud)

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

  1. 您不需要独立跟踪价格和地址,也不需要更改客户的名称变更或礼品购买 - 它已经记录在案.
  2. 使用聚合管道,您可以创建价格趋势,而无需单独存储定价数据.您只需将项目的当前价格存储在订单文档中.
  3. 即使是复杂的聚合,例如价格弹性,州/市等的营业额,也可以使用非常简单的聚合来完成.

一般来说,可以肯定地说,在面向文档的数据库中,将来可能发生变化的每个属性或字段以及这种变化都会产生不同的语义,应该存储在文档中.在将来可能发生变化但未触及语义含义的所有内容(示例中的用户密码)可以通过GUID链接.


xam*_*mir 9

一对多关系

在这种关系中,有许多,许多实体或许多实体映射到一个实体.例如: - 一个城市有很多人住在那个城市.说纽约有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个集合最适合链接.但是对于少数人来说,一个单一的集合通常就足够了.