如何在 MongoDB 聚合管道中隐藏单个子文档?
How do I hide a single subdocument in a MongoDB aggregation pipeline?
在 find()
查询中,您可以在第二个参数中使用 projection 文档隐藏字段:
var cursor = collection.find(query, {
'_id': false,
'unwanted': false
});
它将return 文档中的任何字段和子文档。这是有道理的。
为什么将此 projection
文档放入 aggregation pipeline
时规则会有所不同? $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
和一个 unwanted
子文档除外。我想删除那两个。
更新:
这个问题好像说不清楚,因为讨论的是逻辑而不是问题。那么让我来说明一个低效的解决方案:
// 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;
}
})
我不喜欢这样,因为将 cursor
呈现为 array
会产生开销,并且仅限于 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
.
中的字段排除功能的原因
在 find()
查询中,您可以在第二个参数中使用 projection 文档隐藏字段:
var cursor = collection.find(query, {
'_id': false,
'unwanted': false
});
它将return 文档中的任何字段和子文档。这是有道理的。
为什么将此 projection
文档放入 aggregation pipeline
时规则会有所不同? $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
和一个 unwanted
子文档除外。我想删除那两个。
更新:
这个问题好像说不清楚,因为讨论的是逻辑而不是问题。那么让我来说明一个低效的解决方案:
// 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;
}
})
我不喜欢这样,因为将 cursor
呈现为 array
会产生开销,并且仅限于 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
.