使用mongoosejs填充和直接对象包含之间是否有性能差异(查询的处理时间)?什么时候应该使用?
猫鼬人口的例子:
var personSchema = Schema({
_id : Number,
name : String,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
});
猫鼬对象嵌套示例:
var personSchema = Schema({
_id : Number,
name : String,
stories : [storySchema]
});
var storySchema = Schema({
_creator : personSchema,
title : String,
});
关于猫鼬种群的第一件事,是要了解它不是魔术,而只是一种方便的方法,它使您无需亲自完成所有操作即可检索相关信息。
该概念主要用于以下情况:您决定需要将数据放置在单独的集合中,而不是将数据嵌入其中,并且主要考虑因素通常应在文档大小上,或者在相关信息会经常更新的情况下,难以维护嵌入式数据。
“非魔术”部分实际上是在幕后发生的事情是,当您“引用”另一个源时,填充函数会对“相关”集合进行附加查询/查询,以“合并”父项的结果您检索到的对象。您可以自己执行此操作,但是此处提供的方法是为了方便简化任务。明显的“性能”考虑因素是,没有一个往返数据库(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的答案。为了避免将数据拆分为归一化的集合,您尝试将“相关”数据直接嵌入使用它的文档中。此处的优点是,存在一个用于检索“相关”信息的“读取”操作,以及一个用于更新“父”和“子”条目的“写”操作的单点,尽管通常无法写入一次“许多”子级,而不处理客户端上的“列表”或接受“多个”写入操作,最好不进行“批处理”处理。
然后数据看起来像这样(与上面的示例相比):
{
"_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个或更多条目。
嵌入的数据通常不需要频繁更改。因此,您可以忍受来自非规范化的“重复”,而不需要在许多父文档中使用相同的信息来更新这些“重复”以调用更改。
相关数据经常与父级关联使用。这意味着,如果您的“读/写”用例几乎总是需要同时对父级和子级进行“读/写”,则为原子操作嵌入数据是有意义的。
相关数据将始终超过16MB BSON限制。您始终可以考虑使用“存储桶”的混合方法,但是不能违反主文档的一般硬性限制。常见的情况是“发布”和“评论”,其中“评论”活动预计会很大。
相关数据需要定期更新。或实质上是您进行“规范化”的情况,因为该数据在许多父级之间“共享”并且“相关”数据被频繁更改,以至于在发生“子级”项的每个“父级”中更新嵌入项都是不切实际的。更简单的情况是仅引用“子项”并进行一次更改。
读写之间有明显的区别。如果您在阅读“父母”时可能不会总是要求“相关”信息,或者在写给孩子时不一定要始终更改“父母”,则可能有充分的理由分离模型作为参考。另外,如果普遍希望一次更新许多“子文档”,而这些“子文档”实际上是对另一个集合的引用,那么当数据位于单独的位置时,实现通常会更高效采集。
因此,实际上在MongoDB 数据建模文档中,关于哪个位置的“利弊”讨论都更为广泛,涵盖了各种用例以及由populate方法支持的使用嵌入或引用模型的方法。
希望可以使用“点”,但通常的建议是考虑应用程序的数据使用模式并选择最佳的模式。选择“应该”来嵌入“应该”是您选择MongoDB的原因,但实际上这将是您的应用程序“使用数据”的方式,从而决定哪种方法适合数据建模的哪一部分(因为并非如此)
“全有还是全无”)最好。
1.
请注意,由于这是最初编写的,因此MongoDB引入了$lookup
运算符,该运算符的确在服务器上的集合之间执行“联接”。出于此处一般性讨论的目的,在大多数情况下,“更好”是由“多重查询”引起的开销,而在一般情况下是“多重查询”
populate()
,因此任何操作仍然存在
“大量开销”$lookup
。
核心设计原则是“嵌入”的意思是“已经存在”,而不是“从其他地方获取”。本质上,“放在口袋里”和“在书架上”之间的区别,以及在I /
O术语上的区别通常更像是 “在市中心图书馆的书架上” ,对于基于网络的请求尤其明显。
问题内容: 只是一个简单的查询,例如在模型中使用双引用。 模式/模型 询问 我已经尝试过类似的东西 实际上,只有人口之一在工作。 那么,如何让两个人口工作呢? 问题答案: 您已经在使用以下正确的语法: 也许订单中的ObjectId不在集合中?
我有一个java类,类似于 我的ibatis查询是:,我想要的结果映射是这样的,我可以在其中填充b类(b.b、b.c)的属性。 你知道我如何从ibatis查询中填充这个对象A,从而填充所有3个A、b、c属性吗?
我有一个要填充信息的对象。我从许多不同的服务中检索信息。我做了一个助手类,它有一个公共方法,然后有许多私有方法来调用服务。我写的东西很好,但我不确定这是否是正确的方法。 您可能想知道为什么我需要一个包含所有这些信息的对象。我需要它全部在一个对象中,因为我从这个java对象创建了一个json对象并将其传递给javascript层。 我的方法有什么问题?我是否应该遵循一种编程范式来做这样的事情? 例子
假设我有这样一个模型 和这样的文档。 如果我执行以下操作,页面将永远不会加载。 如果里面有一个实际的ObjectID,它可以正常工作,但当它是空白的时候就不行了。 如果值中没有ObjectID,是否有一种方法可以默认为null?
问题内容: 我有抽象类Human,这是另外两个类Student和Worker的延伸。我正在尝试填写两个数组列表。类型为Student的ArrayList和类型为Worker的ArrayList动态。 } } } } 问题答案: 当然,只需添加学生: 您可以为工人做几乎完全相同的事情。如果要使用循环,请执行以下操作: 这将创建一个新学生列表,其姓名后面有不同的编号。但是,如果您需要其他数据,则该数据
问题内容: 我使用Mongoose.js,无法解决3级层次结构文档的问题。 有2种方法可以做到。 首先 -没有裁判。 我需要出示C记录。仅知道_id的C,如何填充/找到它? 我曾尝试使用: 但是我不知道如何从returnet得到一个对象,我只需要c对象。 其次,如果使用裁判: 如何填充所有B,C记录以获取层次结构? 我试图使用这样的东西: 但是它将为single_c.title返回undefine