从MongoDB集合中获取前N个和后N个记录

时间:2017-12-14 20:50:12

标签: mongodb aggregation-framework

我有一个用例,我需要显示来自组和排序聚合的前10个和后10个结果。我尝试使用$limit,但这不会让下一个聚合器处理完整的数据。

db.collection.aggregate([groupAggregator, sortAggregator, { $limit: 10 }, /*only 10 records available*/] 

如何在管道中间对整个集合执行聚合?我正在使用MongoDB 3.2.9。如果那是不可能的话,UNION有两种聚合方式,第一种是top 10 (ASC SORTED),第二种是last 10 (DESC SORTED)

如果没有用于群组聚合,我会使用db.collection.find({}).sort().filter()策略,但该小组需要完成。

从组聚合中获取的数据

{_id: "", ..., avg_count: 10}
{_id: "", ..., avg_count: 1}
{_id: "", ..., avg_count: 2}
{_id: "", ..., avg_count: 5}
{_id: "", ..., avg_count: 8}
{_id: "", ..., avg_count: 3}
{_id: "", ..., avg_count: 4}
{_id: "", ..., avg_count: 6}
{_id: "", ..., avg_count: 7}
{_id: "", ..., avg_count: 9}

从排序聚合

获得的数据
{_id: "", ..., avg_count: 1}
{_id: "", ..., avg_count: 2}
{_id: "", ..., avg_count: 3}
{_id: "", ..., avg_count: 4}
{_id: "", ..., avg_count: 5}
{_id: "", ..., avg_count: 6}
{_id: "", ..., avg_count: 7}
{_id: "", ..., avg_count: 8}
{_id: "", ..., avg_count: 9}
{_id: "", ..., avg_count: 10}

期望的输出:

  

FETCH FIRST 2和最后2个文件

{_id: "", ..., avg_count: 1}
{_id: "", ..., avg_count: 2}
{_id: "", ..., avg_count: 9}
{_id: "", ..., avg_count: 10}

注意:以上只是一个示例数据,实际数据没有确切的序列号。

1 个答案:

答案 0 :(得分:2)

如果理解正确,这是获得该行为的一种方式:

db.collection.aggregate([{
    $sort: { "your_sort_field": 1 } // sort the data
}, {
    $group: {
        _id: null, // group everything into one single bucket
        docs: { $push: "$$ROOT" } // push all documents into an array (this will be massive for huge collections...)
    }
}, {
    $project: {
        "docsTop10": { $slice: [ "$docs", 10 ] }, // take the first 10 elements from the ASC sorted array
        "docsBottom10": { $reverseArray: { $slice: [ "$docs", -10 ] } } // take the last 10 elements from the array but reverse their order
    }
}])

如果您希望将所有内容都放在一个属性中,则可以在最后阶段使用$concatArrays

$project: {
    "result": { $concatArrays: [ { $slice: [ "$docs", 10 ] }, { $reverseArray: { $slice: [ "$docs", -10 ] } } ] }
}

不幸的是,你的MongoDB版本还没有$replaceRoot,否则你可以更好地平整结果。

此外,由于$reverseArray似乎在v3.2中也不可用,因此您可以在{{3}之后再删除该运算符$unwind$sort。阶段:

{
    $project: {
        _id: 0,
        "result": { $concatArrays: [ { $slice: [ "$docs", 10 ] }, { $slice: [ "$docs", -10 ] } ] }
    }
}, {
    $unwind: "$result"
}, {
    $sort: { "result.your_sort_field": 1 } // sort the data
}

另一种选择是使用$project(仅从v3.4开始),这肯定会更快,因为MongoDB能够很好地优化排序/限制组合:

db.collection.aggregate([{
    $facet: { // start two separate pipeline
        "docsTop10": [
            { $sort: { "your_sort_field": 1 } }, // sort ASC
            { $limit: 10 } // take top 10
        ],
        "docsBottom10": [
            { $sort: { "your_sort_field": -1 } }, // sort DESC
            { $limit: 10 } // take top 10
        ]
    }
}])
相关问题