MongoDb:如何从文档中获取字段(子文档)?

胖幻想

考虑以下示例集合:

 {
    "_id:"0,
    "firstname":"Tom",
    "children" : {
                    "childA":{
                                "toys":{
                                        'toy 1':'batman',
                                        'toy 2':'car',
                                        'toy 3':'train',
                                        }
                                "movies": {
                                        'movie 1': "Ironman"
                                        'movie 2': "Deathwish"
                                        }
                                },
                    "childB":{
                                "toys":{
                                        'toy 1':'doll',
                                        'toy 2':'bike',
                                        'toy 3':'xbox',
                                        }
                                "movies": {
                                        'movie 1': "Frozen"
                                        'movie 2': "Barbie"
                                        }
                                }
                    }
}

现在,我只想检索特定文档中的电影。

我已经尝试过这样的事情:

movies = users.find_one({'_id': 0}, {'_id': 0, 'children.ChildA.movies': 1})

但是,我了解了从“孩子”到“电影”的整个领域结构,这是内容。我该如何查询并仅检索“电影”的内容?

具体来说,我想以此结束:

                                       {
                                        'movie 1': "Frozen"
                                        'movie 2': "Barbie"
                                        }
尼尔·伦恩

这里的问题是您当前的数据结构对于查询而言确实不是很好。这主要是因为您使用“键”来实际表示“数据点”,尽管最初看起来似乎是一个合理的想法,但这实际上是一个非常糟糕的做法。

因此,与其执行诸如将“ childA”和“ childB”分配为对象或“子文档”的键之类的事情,不如将这些“值”分配给如下结构的通用键名:

 {
    "_id:"0,
    "firstname":"Tom",
    "children" : [
        { 
            "name": "childA", 
            "toys": [
                "batman",
                "car",
                "train"
            ],
            "movies": [
                "Ironman"
                "Deathwish"
            ]
        },
        {
            "name": "childB",
            "toys": [
                "doll",
                "bike",
                "xbox",
            ],
            "movies": [
                "Frozen",
                "Barbie"
            ]
        }
    ]
}

这不是最好的方法,因为存在嵌套数组,这可能是一个潜在的问题,但是对此也有解决方法(但稍后介绍),但是这里的要点是,这比在“键”中定义数据要好得多。而且,未统一命名的“键”的主要问题在于,MongoDB通常不允许以任何方式对这些名称进行“通配符”,因此您必须使用命名和“绝对路径”来访问元素,如下所示:

孩子-> childA->玩具
孩子-> childB->玩具

简而言之,这不好的,并且与之相比:

"children.toys"

从上面制备的样品,那么我会说这是一个整体很多更好的方法来组织数据。

即使这样,仅取回诸如“电影的唯一列表”之.find()类的内容对于MongoDB中的标准类型查询也是超出范围的实际上,这需要更多的“文档操作”,并且在MongoDB的聚合框架中得到了很好的支持。它具有查询方法中不存在的广泛操作功能,并且对于具有上述结构的每个文档,您可以执行以下操作:

db.collection.aggregate([
    # De-normalize the array content first
    { "$unwind": "$children" },

    # De-normalize the content from the inner array as well
    { "$unwind": "$children.movies" },

    # Group back, well optionally, but just the "movies" per document
    { "$group": {
        "_id": "$_id",
        "movies": { "$addToSet": "$children.movies" }
    }}
])

因此,现在文档中的“列表”响应仅包含“独特”电影,这与您要问的内容更加对应。或者,您可以$push改为创建“非唯一”列表。但愚蠢的实际上是这样的:

db.collection.find({},{ "_id": False, "children.movies": True })

作为一个“集合范围”的概念,那么您可以通过简单地使用该.distinct()方法将其简化很多它基本上根据您提供的输入形成“独特”键的列表。这可以很好地与数组一起玩:

db.collection.distinct("children.toys")

从本质上讲,这是对集合中每个“玩具”值的所有“不同”事件的集合范围的分析,并以简单的“数组”形式返回。


但是,对于您现有的结构,它应该有一个解决方案来解释,但是您确实必须理解该解释是可怕的。这里的问题是,通用查询和聚合方法可用的“本机”和优化方法根本不可用,唯一可用的选项是基于JavaScript的处理。这即使通过更好的“V8”引擎整合了一下,仍然是真正的完全没精打采时,通过与本地代码的方法相比,侧方。

因此,从您拥有的“原始”表单中(JavaScript表单,函数必须非常易于翻译”):

 db.collection.mapReduce(
     // Mapper
     function() {
         var id this._id;
             children = this.children;

         Object.keys(children).forEach(function(child) {
             Object.keys(child).forEach(function(childKey) {
                 Object.keys(childKey).forEach(function(toy) {
                     emit(
                         id, { "toys": [children[childkey]["toys"][toy]] }
                     );
                 });
             });
         });
     },
     // Reducer
     function(key,values) {
         var output = { "toys": [] };

         values.forEach(function(value) {
             value.toys.forEach(function(toy) {
                 if ( ouput.toys.indexOf( toy ) == -1 )
                     output.toys.push( toy );
             });
         });
     },
     {
         "out": { "inline": 1 }
     }
)

因此,JavaScript评估是一种“可怕”的方法,因为它的执行速度要慢得多,并且您会看到需要实现的“遍历”代码。对性能来说是个坏消息,所以不要这样做。改为更改结构。


最后,您可以对此模型进行建模以避免“嵌套数组”的概念。并了解“嵌套数组”唯一真正问题是,如果不阅读整个文档并对其进行修改,则“更新”嵌套元素实际上是不可能的。

因此$push$pull方法工作正常。但是使用“位置”$运算符只是行不通,因为“外部”数组索引始终是“第一个”匹配元素。因此,如果这确实是您的问题,则可以执行以下操作,例如:

 {
    "_id:"0,
    "firstname":"Tom",
    "childtoys" : [
        { 
            "name": "childA", 
            "toy": "batman"
        }.
        { 
            "name": "childA",
            "toy": "car"
        },
        {
            "name": "childA",
            "toy": "train"
        },
        {
            "name": "childB",
            "toy": "doll"
        },
        {
            "name": "childB",
            "toy": "bike"
        },
        {
            "name": "childB",
            "toy": "xbox"
        }
    ],
    "childMovies": [
        {
             "name": "childA"
             "movie": "Ironman"
       },
       {
            "name": "childA",
            "movie": "Deathwish"
       },
       {
            "name": "childB",
            "movie": "Frozen"
       },
       {
            "name": "childB",
            "movie": "Barbie"
       }
  ]
}

如果确实确实需要定期“更新”项目,而不仅仅是将“ push”和“ $ pull”项目添加到“ toys”和“ movies”数组中,那将是避免嵌套更新的一种方法。

但是这里的总体信息是围绕您实际使用的访问模式来设计数据。在能够查询或以其他方式灵活地发布更新方面,MongoDB通常不喜欢带有“严格路径”的事物。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何从嵌套数组中获取字段和值并查询它们以在 mongodb 中查找文档?

如何从 Firestore 中的多层文档中获取字段

从 Firestore 文档中获取字段

如何使用MongoDB中文档中的字段更新子文档数组中的字段?

如何在MongoDb中查找与数组中的字段和子文档字段匹配的文档

如何在MongoDB的子文档中添加额外的字段?

如何在MongoDB中更新子文档字段值?

如何在mongodb中的所有文档中的子文档数组中添加字段?

如何在MongoDB中具有相同字段的子文档,多文档中重新注册?

MongoDB:重命名集合中的字段(文档和子文档)

firestore 从集合中的所有文档中获取字段

获取MongoDB文档中的字段列表?

Elasticsearch从所有文档中获取字段的值

Kotlin Firestore-从特定文档中获取字段

如何在mongoDB中对文档进行分组并获取文档计数以及获取子文档的平均值

如何从mongodb获取匹配的子文档?

如何从mongodb获取Geowithin匹配的子文档?

从具有标准 Mongodb Dart 的文档中获取子文档

MongoDB:在子文档中获取最大日期并保持文档结构

如何从每个主文档的 Mongodb 子文档中获取唯一和总计数

如何使用C#驱动程序更新MongoDB中数组子文档中包含的数组子文档中的字段?

如何更新mongodb中的文档字段?

如何从MongoDB文档中完全删除字段?

如何将mongodb字段转换为子文档字段?

如何获取Firestore文档中的字段?

如何在mongodb中更新子文档

如何在MongoDB中查询子文档?

如何过滤mongoDB中的子文档?

MongoDB:如何在不指定数组索引的任何字段的子文档中查找包含字符串的文档?