MongoDB首选的嵌入式集合模式.文档vs.数组



我相信至少有两种方法可以在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是很重要的。

我想知道这两种模式之间是否有优缺点。特别是在使用索引时,我觉得第二种方法可能更容易使用,因为可以在"行"上创建索引。Id '或'lines.name'来在所有文档中搜索Id或名称。在第一个示例中,我没有找到任何有效的解决方案来索引id ('idk73716'等)。

如果您有这样的用例,通常更倾向于使用第二种方法吗?

在第一种方法中,您不能索引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" } } }

空{}表示查询,第二部分{'行。Idk73716 ':1}是一个查询选择器。

将id作为键具有单独选择特定字段的优势。即使{'行。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"
    }
] }

希望有帮助

编辑

感谢@盖茨副总裁指出

db.your_collection.find({'lines.idk73716':{$exists:true}})。如果你想要使用"id作为键"的版本,exists查询可以工作,但是它不能被索引

我们仍然可以使用$exists来查询id,但是它不能被索引

今天我们有$eleMatch操作符来实现这一点,正如这里所讨论的——只检索MongoDB集合中对象数组中查询的元素

但是这个问题提出了一些有趣的设计选择,我今天也在努力做出选择。如果在嵌入式文档中需要频繁的CRUD,那么从给定的两个选项中应该选择哪个?

我发现,当ID用作属性名时,使用新的$set/$unset操作符很容易在嵌入文档上执行CRUD。如果客户端可以获得ID进行编辑,这比数组要好。这是Mongodb关于模式设计和做出这些设计决策的另一篇有用的博文

http://blog.mongodb.org/post/87200945828/6-rules-of-thumb-for-mongodb-schema-design-part-1

最新更新