关于mongoose 种群,首先要了解的是,它不是魔法,只是一种方便的方法,可以让你在不必自己动手的情况下检索相关信息.
基本上,当您决定需要将数据放在一个单独的集合中,而不是嵌入该数据时,可以使用该概念,并且您的主要考虑因素通常应该是文档大小,或者相关信息需要频繁更新,这会使维护嵌入的数据变得非常困难.
"不神奇"的部分是,本质上,当您"引用"另一个源时,populate函数会对该"相关"集合进行额外的查询,以便"合并"您检索到的父对象的结果.你可以自己做这件事,但是这个方法是为了简化任务.显而易见的"性能"考虑因素是,为了检索所有信息,没有一次到数据库(MongoDB实例)的往返.总有不止一个.
作为一个样本,选取两个系列:
{
"_id": ObjectId("5392fea00ff066b7d533a765"),
"customerName": "Bill",
"items": [
ObjectId("5392fee10ff066b7d533a766"),
ObjectId("5392fefe0ff066b7d533a767")
]
}
以及以下项目:
{ "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 }
{ "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }
"参考"模型或使用填充(在引擎盖下)可以做到的"最佳"是:
var order = db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });
order.items = db.items.find({ "_id": { "$in": order.items } ).toArray();
因此,为了"连接"这些数据,显然"至少"有两个查询和操作.
嵌入概念本质上是MongoDB对如何处理不支持"joins"1的回答.因此,与其将数据拆分为规范化的集合,不如try 将"相关"数据直接嵌入到使用它的文档中.这里的优点是,有一个用于检索"相关"信息的"读取"操作,还有一个用于更新"父"和"子"条目的单点"写入"操作,虽然通常不可能在不处理客户机上的"列表"或以其他方式接受"多个"写入操作的情况下同时向"多个"子级写入,最好是在"批处理"处理中.
然后,数据看起来是这样的(与上面的示例相比):
{
"_id": ObjectId("5392fea00ff066b7d533a765"),
"customerName": "Bill",
"items": [
{ "_id": ObjectId("5392fee10ff066b7d533a766"), "prod": "ABC", "qty": 1 },
{ "_id": ObjectId("5392fefe0ff066b7d533a767"), "prod": "XYZ", "qty": 2 }
]
}
因此,实际获取数据只是一个问题:
db.orders.findOne({ "_id": ObjectId("5392fea00ff066b7d533a765") });
两者的利弊在很大程度上取决于应用程序的使用模式.但乍一看:
嵌入
嵌入数据的文档总大小通常不会超过16MB的存储空间(BSON限制),或者(作为指导原则)具有包含500个或更多条目的array.
嵌入的数据通常不需要频繁更改.因此,您可以接受来自go 规范化的"重复",而不需要在许多父文档中使用相同的信息来更新这些"重复",只是为了调用更改.
相关数据经常与父级关联使用.这意味着,如果您的"读/写" case 几乎总是需要对父级和子级进行"读/写",那么嵌入用于原子操作的数据是有意义的.
引用
相关数据总是会超过16MB BSON限制.你总是可以考虑一种混合的"ButkTebug"方法,但是主文档的一般硬限制不能被 destruct .常见的情况是"发布"和" comments ",其中" comments "活动预计会非常大.
相关数据需要定期更新.或者基本上是"标准化"的情况,因为该数据在多个父级之间"共享",并且"相关"数据的更改足够频繁,以至于在出现该"子"项的每个"父级"中更新嵌入的项是不切实际的.更简单的情况是只引用"child"并进行一次更改.
读写之间有明确的分离.如果您在阅读"家长"时可能并不总是需要"相关"信息,或者在给子元素写信时不需要总是更改"家长",那么就有很好的理由将参考的模型分开.此外,如果普遍希望同时更新多个"子文档",其中这些"子文档"实际上是对另一个集合的引用,那么当数据位于单独的集合中时,实现通常更高效.
因此,对于MongoDB文档Data Modelling中的任何一种立场,实际上都有更广泛的"优缺点"讨论,其中涵盖了各种用例,以及使用填充方法支持的嵌入或引用模型的方法.
希望"点"是有用的,但一般的建议是考虑应用程序的数据使用模式,并 Select 什么是最好的. Select MongoDB的原因是有"选项"嵌入"应该",但实际上是应用程序"使用数据"的方式决定了哪种方法最适合数据建模的哪一部分(因为它不是"全部或全部").
- 请注意,由于这是最初编写的,MongoDB引入了
$lookup
操作符,它确实在服务器上的集合之间执行"连接".在这里进行一般性讨论时,whist"更好"在大多数情况下,populate()
和"多个查询"产生的"多个查询"开销一般来说,任何$lookup
个操作都会产生"significant overhead".
核心设计原则是"嵌入式"意味着"已经存在",而不是"从其他地方获取".本质上是"在你的口袋里"和"在架子上"之间的区别,在I/O术语中,通常更像是"on the shelf in the library downtown",尤其是对于基于网络的请求来说,距离更远.