MongoDB - $project 嵌套文档到根级别 [英] MongoDB - $project nested document to root level

查看:28
本文介绍了MongoDB - $project 嵌套文档到根级别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以不写所​​有子文档的字段?

假设我有以下文档结构:

Let's say I have the following document structure:

{
  field1: a,
  subdoc: {
          field2: b,
          field3: c
  }
}

我想使用 $project 来获取 root 级别的 suboc:

I want to use $project in order to get the suboc at root level:

{
  field1: a,
  field2: b,
  field3: c              
}

这只是subdoc中有2个字段的例子,我的真实文档有很多字段,以后可能会添加或删除更多,所以我希望$project更加动态而不是单独指定所有字段.

This is just an example with 2 fields in the subdoc, my real document has many fields and more may be added or deleted in the future, so I want the $project to be more dynamic and not to specify all the fields separately.

推荐答案

对于 MongoDB 3.6 及更新版本,使用带有 $replaceRoot 管道,可与 $mergeObjects 操作符作为 newRoot 表达式.

For MongoDB 3.6 and newer, use aggregation framework with a $replaceRoot pipeline that can be applied in conjunction with the $mergeObjects operator as the newRoot expression.

这个表达

{ "$mergeObjects": ["$subdoc", "$$ROOT"] }

将文档中的顶级字段与子文档嵌入字段中的字段合并,因此最终您的聚合操作将如下所示:

will merge the top level fields in the document with the ones in the subdoc embedded fields so in the end your aggregate operation will be as follows:

db.collection.aggregate([
    { "$replaceRoot": { 
        "newRoot": { 
            "$mergeObjects": [ "$subdoc", "$$ROOT" ] 
        } 
    } },
    { "$project": { "subdoc": 0 } }  
])

<小时>

否则,您将需要一种机制来获取组装动态 $project 文档所需的所有动态密钥.这可以通过 Map-Reduce.以下 mapreduce 操作将使用所有键作为 _id 值填充一个单独的集合:


Otherwise you would need a mechanism to get all the dynamic keys that you need to assemble the dynamic $project document. This is possible through Map-Reduce. The following mapreduce operation will populate a separate collection with all the keys as the _id values:

mr = db.runCommand({
    "mapreduce": "my_collection",
    "map" : function() {
        for (var key in this.subdoc) { emit(key, null); }
    },
    "reduce" : function(key, stuff) { return null; }, 
    "out": "my_collection" + "_keys"
})

要获取所有动态键的列表,请在结果集合上运行 distinct :

To get a list of all the dynamic keys, run distinct on the resulting collection:

db[mr.result].distinct("_id")
["field2", "field3", ...]

现在给出上面的列表,您可以通过创建一个在循环中设置其属性的对象来组装您的 $project 聚合管道文档.通常,您的 $project 文档将具有以下结构:

Now given the list above, you can assemble your $project aggregation pipeline document by creating an object that will have its properties set within a loop. Normally your $project document will have this structure:

var project = {
    "$project": {
        "field1": 1,
        "field2": "$subdoc.field2",
        "field3": "$subdoc.field3"
    }
};

因此,使用上面的子文档键列表,您可以使用 JavaScript 的 reduce() 方法:

So using the above list of subdocument keys, you can dynamically construct the above using JavaScript's reduce() method:

var subdocKeys = db[mr.result].distinct("_id"),
    obj = subdocKeys.reduce(function (o, v){
      o[v] = "$subdoc." + v;
      return o;
    }, { "field1": 1 }),
    project = { "$project": obj };

db.collection.aggregate([project]);

这篇关于MongoDB - $project 嵌套文档到根级别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆