用于嵌入式集合的 MongoDB 首选模式。文档与数组
Posted
技术标签:
【中文标题】用于嵌入式集合的 MongoDB 首选模式。文档与数组【英文标题】:MongoDB preferred schema for embedded collections. documents vs. arrays 【发布时间】:2011-12-26 00:35:29 【问题描述】:我相信至少有两种方法可以在 mongodb 文档中嵌入数据。在一个简化的例子中,我们可以有这样的东西:
'name' : 'bill',
'lines':
'idk73716': 'name': 'Line A',
'idk51232': 'name': 'Line B',
'idk23321': 'name': 'Line C'
作为一个数组:
'name' : 'bill',
'lines': [
'id': 'idk73716', 'name': 'Line A',
'id': 'idk51232', 'name': 'Line B',
'id': 'idk23321', 'name': 'Line C'
]
正如您在此用例中所见,保留每行的 id 很重要。
我想知道这两种模式之间是否有优缺点。特别是在使用索引时,我觉得第二种可能更容易使用,因为可以在“lines.id”甚至“lines.name”上创建一个索引来搜索所有文档的 id 或名称。在第一个示例中,我没有找到任何有效的解决方案来索引 id('idk73716' 等)。
如果您有这样的用例,通常是否首选使用第二种方法?
【问题讨论】:
【参考方案1】:今天我们有 $eleMatch 运算符来实现这一点,正如这里所讨论的 - Retrieve only the queried element in an object array in MongoDB collection
但是这个问题提出了一些有趣的设计选择,我今天也在努力做出这些选择。 如果在嵌入式文档中需要频繁的 CRUD,那么从给定的两个选项中应该首选哪一个?
我发现,当 ID 用作属性名称时,使用新的 $set/$unset 运算符在嵌入式文档上执行 CRUD 很容易。而且如果客户可以获取ID进行编辑,它比数组,IMO更好。 这是 Mongodb 关于模式设计和做出这些设计决策的另一篇有用的博文
http://blog.mongodb.org/post/87200945828/6-rules-of-thumb-for-mongodb-schema-design-part-1
【讨论】:
【参考方案2】:在您的第一种方法中,您无法索引 id 字段,因为 id 用作键。它有点像键值字典。如果您有一组已知的 id(当然数量较少),这种方法很有用。假设在您的第一个示例中,id 在前面是众所周知的,
>>db.your_colleection.find()
"_id" : ObjectId("4ebbb6f974235464de49c3a5"), "name" : "bill",
"lines" :
"idk73716" : "name" : "Line A" ,
"idk51232" : "name" : "Line B" ,
"idk23321": "name" : "Line C"
所以要查找 id 字段 idk73716 的值,您可以通过
db.your_colleection.find(,'lines.idk73716':1)
"_id" : ObjectId("4ebbb6f974235464de49c3a5"), "lines" : "idk73716" : "name" : "Line A"
空的 表示查询,第二部分 'lines.idk73716':1 是查询选择器。
将 id 作为键具有单独选择特定字段的优势。 尽管 'lines.idk73716':1 是一个字段选择器,但在这里它用作查询和选择器。但这不能在您的第二种方法中完成。假设第二个集合是这样的
> db.second_collection.find()
"_id" : ObjectId("4ebbb9c174235464de49c3a6"), "name" : "bill", "lines" : [
"id" : "idk73716",
"name" : "Line A"
,
"id" : "idk51232",
"name" : "Line B"
,
"id" : "idk23321",
"name" : "Line C"
]
>
并且你索引了字段id,所以如果你想通过id查询
> db.second_collection.find('lines.id' : 'idk73716' )
"_id" : ObjectId("4ebbb9c174235464de49c3a6"), "name" : "bill", "lines" : [
"id" : "idk73716",
"name" : "Line A"
,
"id" : "idk51232",
"name" : "Line B"
,
"id" : "idk23321",
"name" : "Line C"
]
>
通过查看上面的输出,可以看出没有办法单独选择匹配的子(嵌入)文档,但在第一种方法中是可能的。这是 mongodb 的默认行为。
见
db.second_collection.find('lines.id' : 'idk73716' ,'lines':1)
将获取所有行,而不仅仅是 idk73716
"_id" : ObjectId("4ebbb9c174235464de49c3a6"), "lines" : [
"id" : "idk73716",
"name" : "Line A"
,
"id" : "idk51232",
"name" : "Line B"
,
"id" : "idk23321",
"name" : "Line C"
]
希望对你有帮助
编辑
感谢@Gates VP指出
db.your_collection.find('lines.idk73716':$exists:true)
。如果你 想要使用“ids as keys”版本,exists 查询可以工作,但是 它不能被索引
我们仍然可以使用 $exists 来查询 id,但它不会被索引
【讨论】:
非常感谢您提供详细而快速的解决方案。我已经尝试了您的查询,发现不幸的是“db.your_colleection.find(,'lines.idk73716':1)”将查询并返回所有文档,但如果文档有,则仅返回 lines.idk73716 部分一。确实,只选择这一特定行是一个优势,但是由于 过滤器,结果包括集合的所有文档。 @antons,是的,这就是两种方法之间的区别......第二种方法最适合查询。 first 只有在您知道要使用的文档时才有用... 好的,很酷。这是一个很好的结论。就我而言,快速找到包含“idk73716”行的文档更为重要。所以我想说第二种方法可能最适合我的情况。 我认为在此处添加以下内容很重要:`db.your_collection.find('lines.idk73716':$exists:true)`。如果你想使用“ids as keys”版本,exists 查询可以工作,但它不能被索引。 第二种方法还保证lines
将按特定顺序排列。以上是关于用于嵌入式集合的 MongoDB 首选模式。文档与数组的主要内容,如果未能解决你的问题,请参考以下文章