我想在查询时对嵌套数组进行排序,同时投影文档中的所有字段。
示例文档:
{ "_id" : 0, "unknown_field" : "foo", "array_to_sort" : [ { "a" : 3, "b" : 4 }, { "a" : 3, "b" : 3 }, { "a" : 1, "b" : 0 } ] }
我可以通过聚合执行排序,但无法保留我需要的所有字段。应用程序在查询时不知道每个文档中可能出现哪些其他字段,因此我无法显式投影它们。如果我有一个通配符来投影所有字段,那么这将起作用:
db.c.aggregate([
{$unwind: "$array_to_sort"},
{$sort: {"array_to_sort.b":1, "array_to_sort:a": 1}},
{$group: {_id:"$_id", array_to_sort: {$push:"$array_to_sort"}}}
]);
...但不幸的是,它产生的结果不包含“unknown_field”:
{
"_id" : 0,
"array_to_sort" : [
{
"a" : 1,
"b" : 0
},
{
"a" : 3,
"b" : 3
},
{
"a" : 3,
"b" : 4
}
]
}
如果您想尝试一下,这是插入命令:
db.c.insert({"unknown_field": "foo", "array_to_sort": [{"a": 3, "b": 4}, {"a": 3, "b":3}, {"a": 1, "b":0}]})
我无法对数组进行预排序,因为排序标准是动态的。我可以在查询时按 a 和/或 b 升序/降序的任意组合进行排序。我意识到我可能需要在客户端应用程序中执行此操作,但如果我可以在 mongo 中执行此操作,那就太好了,因为这样我还可以 $slice/skip/limit 分页结果,而不是每次都检索整个数组。
最佳答案
由于您要对文档 _id
进行分组,因此您只需将想要保留的字段放入分组 _id
中即可。然后你可以使用$project
重新形成
db.c.aggregate([
{ "$unwind": "$array_to_sort"},
{ "$sort": {"array_to_sort.b":1, "array_to_sort:a": 1}},
{ "$group": {
"_id": {
"_id": "$_id",
"unknown_field": "$unknown_field"
},
"Oarray_to_sort": { "$push":"$array_to_sort"}
}},
{ "$project": {
"_id": "$_id._id",
"unknown_field": "$_id.unknown_field",
"array_to_sort": "$Oarray_to_sort"
}}
]);
其中的另一个“技巧”是在分组阶段为数组使用临时名称。当您$project
时就是这样。并更改名称,您将按照投影语句中指定的顺序获取字段。如果您没有这样做,那么“array_to_sort”字段将不会是顺序中的最后一个字段,因为它是从前一阶段复制的。
这是 $project
中的预期优化,但如果您想要顺序,那么您可以按照上面的方式进行。
对于完全未知的结构,可以使用 mapReduce 的方法:
db.c.mapReduce(
function () {
this["array_to_sort"].sort(function(a,b) {
return a.a - b.a || a.b - b.b;
});
emit( this._id, this );
},
function(){},
{ "out": { "inline": 1 } }
)
当然,它具有特定于 mapReduce 的输出格式,因此不完全是您拥有的文档,但所有字段都包含在“值”下:
{
"results" : [
{
"_id" : 0,
"value" : {
"_id" : 0,
"some_field" : "a",
"array_to_sort" : [
{
"a" : 1,
"b" : 0
},
{
"a" : 3,
"b" : 3
},
{
"a" : 3,
"b" : 4
}
]
}
}
],
}
future 版本(截至撰写本文时)允许您聚合使用 $$ROOT
变量来表示文档:
db.c.aggregate([
{ "$project": {
"_id": "$$ROOT",
"array_to_sort": "$array_to_sort"
}},
{ "$unwind": "$array_to_sort"},
{ "$sort": {"array_to_sort.b":1, "array_to_sort:a": 1}},
{ "$group": {
"_id": "$_id",
"array_to_sort": { "$push":"$array_to_sort"}
}}
]);
因此,使用最后的“项目”阶段是没有意义的,因为您实际上并不了解文档中的其他字段。但它们都将包含在结果文档的 _id
字段中(包括原始数组和 order )。
关于mongodb - 对查询中的数组进行排序并投影所有字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22888885/