是否可以不编写所有子文档的字段?
假设我有以下文档结构:
{
field1: a,
subdoc: {
field2: b,
field3: c
}
}
Run Code Online (Sandbox Code Playgroud)
我想使用$project以获取根级别的 suboc:
{
field1: a,
field2: b,
field3: c
}
Run Code Online (Sandbox Code Playgroud)
这只是 subdoc 中有 2 个字段的示例,我的真实文档有很多字段,将来可能会添加或删除更多字段,因此我希望$project它更加动态,而不是单独指定所有字段。
对于 MongoDB 3.6 和更新版本,使用带有$replaceRoot管道的聚合框架,该管道可以与$mergeObjects运算符一起应用作为newRoot表达式。
这个表情
{ "$mergeObjects": ["$subdoc", "$$ROOT"] }
Run Code Online (Sandbox Code Playgroud)
将文档中的顶级字段与 subdoc 嵌入字段中的字段合并,因此最终您的聚合操作将如下所示:
db.collection.aggregate([
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [ "$subdoc", "$$ROOT" ]
}
} },
{ "$project": { "subdoc": 0 } }
])
Run Code Online (Sandbox Code Playgroud)
否则,您将需要一种机制来获取组装动态$project文档所需的所有动态密钥。这可以通过Map-Reduce 实现。以下 mapreduce 操作将使用所有键作为_id值填充一个单独的集合:
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"
})
Run Code Online (Sandbox Code Playgroud)
要获取所有动态键的列表,请在结果集合上运行 distinct:
db[mr.result].distinct("_id")
["field2", "field3", ...]
Run Code Online (Sandbox Code Playgroud)
现在给出上面的列表,您可以$project通过创建一个在循环中设置其属性的对象来组装聚合管道文档。通常,您的$project文档将具有以下结构:
var project = {
"$project": {
"field1": 1,
"field2": "$subdoc.field2",
"field3": "$subdoc.field3"
}
};
Run Code Online (Sandbox Code Playgroud)
因此,使用上面的子文档键列表,您可以使用 JavaScript 的reduce()方法动态构造上述内容:
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]);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4113 次 |
| 最近记录: |