MongoDB一对多关系

MongoDB一对多关系,mongodb,Mongodb,我开始学习MongoDB,有一刻我问自己如何解决MongoDB中的“一对多”关系设计。在搜索过程中,我在其他帖子/文章中发现了很多评论,比如“你在思考关系”。 好的,我同意。会有一些情况,比如信息重复不会成为问题,比如客户订单 但是,假设您有表:ORDERS,它具有客户购买的产品的嵌入细节结构。 因此,出于这样或那样的原因,您需要更改已经嵌入到多个订单中的产品名称(或其他类型的信息) 最后,您必须在MongoDB中执行一对多关系(也就是说,将ObjectID字段作为链接放置到另一个集合),这样您

我开始学习MongoDB,有一刻我问自己如何解决MongoDB中的“一对多”关系设计。在搜索过程中,我在其他帖子/文章中发现了很多评论,比如“你在思考关系”。 好的,我同意。会有一些情况,比如信息重复不会成为问题,比如客户订单

但是,假设您有表:ORDERS,它具有客户购买的产品的嵌入细节结构。 因此,出于这样或那样的原因,您需要更改已经嵌入到多个订单中的产品名称(或其他类型的信息)

最后,您必须在MongoDB中执行一对多关系(也就是说,将ObjectID字段作为链接放置到另一个集合),这样您就可以解决这个简单的问题,不是吗? 但每次我发现一些关于这方面的文章/评论,都会说这将是Mongo的一个性能缺陷。这有点令人失望


在MongoDB中是否有其他方法可以解决/设计此问题而不会出现性能故障?

问题在于您过度规范了数据。订单是由客户定义的,客户在给定的时间点居住在特定的地点,并在订购时支付特定的有效价格(在应用程序生命周期内可能会发生重大变化,您必须记录这些参数,以及仅在特定时间点有效的其他几个参数。因此,要记录订单(双关语),您需要保留该特定时间点的所有数据。让我举个例子:

{ _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}
  ]
}
通过此数据模型和聚合管道的使用,您有几个优点:

  • 您不需要独立跟踪客户的价格、地址、姓名变更或礼品购买情况,这些都已经记录在案
  • 使用聚合管道,您可以创建价格趋势,而无需单独存储定价数据。您只需将项目的当前价格存储在订单文档中即可
  • 即使是价格弹性、州/市营业额等复杂的聚合,也可以使用相当简单的聚合来完成
  • 一般来说,可以肯定地说,在面向文档的数据库中,将来可能发生更改的每个属性或字段(这种更改将创建不同的语义)都应该存储在文档中。将来可能发生更改但不涉及语义的所有内容都应该存储在文档中(示例中的用户密码)可以通过GUID链接。

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

    让我们假设以下数据模型:

    这是行不通的,因为这将是一个巨大的挑战。让我们试着翻转一下脑袋

    
     //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
    集合。知道我们没有外键约束,我们必须保持一致。因此,这是一个一对多关系。它需要两个集合。对于小的一对少(也是一对多),关系,如博客文章到评论。评论可以作为数组嵌入到文章文档中


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

    我邀请你看看这些博客文章:(以及第1部分和第2部分)别忘了mongodb是一个NoSQL数据库,所以如果你的数据库中有很多这样的关系,你可能应该选择SQL数据库,因为mongodb在这方面的表现总是比较差。这篇博文很好地解释了这一点:@Baptistel Wuaw!感谢你链接的精彩文章。这让我大开眼界,并证实了我的假设是正确的ut MongoDB是对的。正如作者所说:“MongoDB文档告诉您它擅长什么,而不强调它不擅长什么”。所以我觉得最好还是把我的努力放在另一个地方。@BaptisteL:可能是一个好的程序员,但她不是MongoDB专家。读起来好像她只在两个非常简单的MongoDB项目上工作过,做了几个。她嵌套了文档,尽管这是一种多对多关系(剧集/演员)和嵌套了无限元素的数组(社交提要).为她辩护,手册可能没有今天解释的那么好。这个问题更复杂。我找到了一篇解释很好的文章嗨,马库斯,谢谢你花时间回复,但我想我没有解释清楚。我理解你的观点:订单和细节以一定的价格出售,并在某个特定时刻发送到一个地址,我知道n次。如果事实上你的解决方案是正确的,但我一直看到一种关系模式:我们必须使用Id。但我的意思是:假设你的产品名称有一个拼写错误,并且它已经嵌入到许多文档中。因此,在最后,解决方案是有一个Id链接(就像在关系中一样)因此,您可以避免重复数据。那么,使用文档范例有什么意义呢?因为您不会将产品名称添加到其他文档中,而只将在某个时间点有效的产品属性添加到其他文档中,所以这应该不是问题。链接对象不是问题,但必须非常小心地进行
    
     //people
     {
     _id: 1,
     name: 'John Doe',
     gender: gender,
     city: 'NYC'
    }
    
    //city
    {
    _id: 'NYC',
    ...
    }