MongoDB 一对多关系
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25485882/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MongoDB One to Many Relationship
提问by tapatio
I'm starting to learn MongoDB and I at one moment I was asking myself how to solve the “one to many” relationship design in MongoDB. While searching, I found many comments in other posts/articles like ” you are thinking relational “. Ok, I agree. There will be some cases like duplication of information won't be a problem, like in for example, CLIENTS-ORDERS example.
我开始学习 MongoDB,有一段时间我在问自己如何解决 MongoDB 中的“一对多”关系设计。在搜索时,我在其他帖子/文章中发现了许多评论,例如“您正在考虑关系”。好的我同意。在某些情况下,重复信息不会成为问题,例如 CLIENTS-ORDERS 示例。
But, suppose you have the tables: ORDERS, that has an embedded DETAIL structure with the PRODUCTS that a client bought. So for one thing or another, you need to change a product name (or another kind of information) that is already embedded in several orders.
但是,假设您有表:ORDERS,它具有嵌入的 DETAIL 结构,其中包含客户购买的 PRODUCTS。因此,无论如何,您需要更改已嵌入多个订单中的产品名称(或其他类型的信息)。
At the end, you are force to do a one-to-many relashionship in MongoDB (that means, putting the ObjectID field as link to another collection) so you can solve this simple problem, don't you ? But every time I found some article/comment about this, it says that will be a performance fault in Mongo. It's kind of disappointing
最后,您被迫在 MongoDB 中进行一对多的关联(这意味着,将 ObjectID 字段作为另一个集合的链接),这样您就可以解决这个简单的问题,不是吗?但是每次我发现一些关于此的文章/评论时,它都会说这将是 Mongo 的性能错误。这有点令人失望
Is there another way to solve/design this without performance fault in MongoDB ?
有没有另一种方法可以解决/设计这个而不会在 MongoDB 中出现性能错误?
回答by Markus W Mahlberg
The problem is that you over normalize your data. An order is defined by a customer, who lives at a certain place at the given point in time, pays a certain price valid at the time of the order (which might heavily change over the application lifetime and which you have to document anyway and several other parameters which are all valid only in a certain point of time. So to documentan order (pun intended), you need to persist all data for that certain point in time. Let me give you an example:
问题是你过度规范了你的数据。订单由客户定义,该客户在给定的时间点住在某个地方,支付在下订单时有效的特定价格(这可能会在应用程序生命周期内发生重大变化,无论如何您都必须记录下来,还有一些其他所有仅在特定时间点有效的参数。因此,要记录订单(双关语),您需要保留该特定时间点的所有数据。让我举个例子:
{ _id: "order123456789",
date: ISODate("2014-08-01T16:25:00.141Z"),
customer: ObjectId("53fb38f0040980c9960ee270"),
items:[ ObjectId("53fb3940040980c9960ee271"),
ObjectId("53fb3940040980c9960ee272"),
ObjectId("53fb3940040980c9960ee273")
],
Total:400
}
Now, as long as neither the customer nor the details of the items change, you are able to reproduce where this order was sent to, what the prices on the order were and alike. But now what happens if the customer changes it's address? Or if the price of an item changes? You would need to keep track of those changes in their respective documents. It would be mucheasier and sufficiently efficient to store the order like:
现在,只要客户和商品的详细信息均未更改,您就可以重现此订单发送到的位置、订单上的价格等。但是现在如果客户更改其地址会发生什么?或者如果商品的价格发生变化?您需要在各自的文档中跟踪这些更改。存储以下订单会更容易且足够有效:
{
_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}
]
}
With this data model and the usage of aggregation pipelines, you have several advantages:
有了这个数据模型和聚合管道的使用,你有几个优势:
- You don't need to independently keep track of prices and addresses or name changes or gift buys of a customer - it is already documented.
- Using aggregation pipelines, you can create a price trends without the need of storing pricing data independently. You simply store the currentprice of an item in an order document.
- Even complex aggregations such as price elasticity, turnover by state / city and alike can be done using pretty simple aggregations.
- 您不需要独立跟踪客户的价格和地址或姓名更改或礼品购买 - 已经记录在案。
- 使用聚合管道,您可以创建价格趋势,而无需独立存储定价数据。您只需将商品的当前价格存储在订单文档中。
- 即使是复杂的聚合,例如价格弹性、州/城市的营业额等,也可以使用非常简单的聚合来完成。
In general, it is safe to say that in a document oriented database, every property or field which is subject to change in the future and this change would create a different semantic meaning should be stored inside the document. Everything which is subject to change in the future but doesn't touch the semantic meaning (the users password in the example) may be linked via a GUID.
一般来说,可以肯定地说,在面向文档的数据库中,未来可能会发生变化并且这种变化会产生不同语义的每个属性或字段都应该存储在文档中。将来可能会更改但不涉及语义(示例中的用户密码)的所有内容都可以通过 GUID 链接。
回答by xameeramir
One to Many Relations
一对多关系
In this relationship, there is many, many entities or many entities that map to the one entity. e.g.: - a city have many persons who live in that city. Say NYChave 8 million people.
在这种关系中,有许多实体或许多实体映射到一个实体。例如: - 一个城市有很多人住在那个城市。假设纽约市有 800 万人。
Let's assume the below data model:
让我们假设以下数据模型:
//city
{
_id: 1,
name: 'NYC',
area: 30,
people: [{
_id: 1,
name: 'name',
gender: 'gender'
.....
},
....
8 million people data inside this array
....
]
}
This won't work because that's going to be REALLY HUGE. Let's try to flip the head.
这是行不通的,因为那将是非常巨大的。让我们试着翻转头部。
//people
{
_id: 1,
name: 'John Doe',
gender: gender,
city: {
_id: 1,
name: 'NYC',
area: '30'
.....
}
}
Now the problem with this design is that if there are obviously multiple people living in NYC, so we've done a lot of duplication for city data.
现在这个设计的问题是,如果显然有多个人住在纽约市,那么我们对城市数据做了很多重复。
Probably, the best way to model this data is to use true linking.
可能,对这些数据建模的最佳方法是使用真正的链接。
//people
{
_id: 1,
name: 'John Doe',
gender: gender,
city: 'NYC'
}
//city
{
_id: 'NYC',
...
}
In this case, people
collection can be linked to the city
collection. Knowing we don't have foreign key constraints, we've to be consistent about it. So, this is a one to manyrelation. It requires 2 collections. For small one to few (which is also one to many), relations like blog post to comments. Comments can be embedded inside post documents as an array.
在这种情况下,people
集合可以链接到city
集合。知道我们没有外键约束,我们必须对此保持一致。所以,这是一对多的关系。它需要2个集合。对于小的一对多(这也是一对多),关系就像博客文章到评论。评论可以作为数组嵌入到帖子文档中。
So, if it's truly one to many, 2 collections works best with linking. But for one to few, one single collection is generally enough.
因此,如果确实是一对多,则 2 个集合最适合链接。但对于一对多,一个单一的集合通常就足够了。