如何在MongoDB聚合管道中隐藏单个子文档?

在find()查询中,您可以使用第二个参数中的投影文档隐藏字段:

var cursor = collection.find(query, {
    '_id': false,
    'unwanted': false
});

它将返回文档中的任何字段和子文档.这是有道理的.

将此投影文档放入聚合管道时,为什么规则会有所不同? $project不能正常工作:

var cursor = collection.aggregate([
    {
        $match      : query
    },
    {
        $project    : {
        '_id': false,
        'unwanted': false
        }
    }
]);

问题:

exception: The top-level _id field is the only field currently supported 
for exclusion

如何隐藏特定的子文档而不必明确包含我想要的所有字段?

编辑:除了一些索引字段之外,文档具有任意数量的字段而没有定义的模式.所以我无法指定我想要包含的内容,因为我不知道文档中会有哪些额外的字段.

想象一下带有随机字段的文档,除了_id和不需要的子文档.我想删除这两个.

更新:

看来这个问题还不清楚,因为讨论的是逻辑而不是问题.那么让我来说明一个低效的解决方案:

// node.js

var cursor = collection.aggregate([
    {
        $match     : query
    },
    // ...
]);

cursor.toArray(function(array){
    for (var i = 0; i < array.length; i++) {
        var document = array[i];
        delete document._id;
        delete document.unwanted;
    }
})

我不喜欢这样,因为将光标渲染到数组会产生开销,并且限制为16MB大小的集合.此外,不必执行此操作正是投影文档的用途.

因此我的问题是,为什么我可以使用带投影的find()来获得我的光标,但是不能使用具有相同投影的aggregate()?逻辑在哪里?该功能显然在MongoDB适配器中,否则它也不适用于find().除了刚刚提到的解决方案或解决方法之外,还有哪些可行的解决方案或解决方

我认为一个解决方案可能是使用MongoDB 2.6聚合函数$redact但我无法弄清楚如何使用文档如何简单地删除一个静态子文档.此外,我不想使用它,因为我们的大多数系统都运行MongoDB 2.4.

最佳答案 遗憾的是,您无法在聚合管道中执行此操作,并且在
documentation中已明确定义:

+-----------------------+---------------------------------------------------------+
|                Syntax | Description                                              |
+-----------------------+---------------------------------------------------------+
|  <field>: <1 or true> | Specify the inclusion of a field.                        |
|     _id: <0 or false> | Specify the suppression of the _id field.                |
| <field>: <expression> | Add a new field or reset the value of an existing field. |
+-----------------------+---------------------------------------------------------+

唯一的出路就是你所描述的:

resorting to explicitly including all the fields I want

但无论如何,您可以通过动态构建$project文档来实现这一点,以防您拥有可能出现的所有可能字段.这是一个伪代码:

project_doc = {}
for field in fields
    if field not in to_be_hidden_fields:
        project_doc[field] = "$" + field
return {"$project": project_doc}

这是因为

If you specify an inclusion of a field that does not exist in the document, $project ignores that field inclusion; i.e. $project does not add the field to the document.

然后只需将生成的$project阶段添加到聚合管道中.

但是如果您事先不了解架构,或者甚至不知道生成的文档可能包含的所有可能字段,我认为您应该重新考虑设计.

无论如何,另一个问题出现了,如果你不了解这些字段,你将如何进行聚合?我认为这就是为什么MongoDB消除了$project中的字段排除功能的原因.

点赞