Mongo组和排序不按正确顺序提供数据

时间:2018-02-27 13:37:44

标签: php mongodb mongodb-query aggregation-framework

我在search_analytics集合中关注文档

<resource-file>

现在,我希望获得最近创建的文档所排序的唯一搜索关键字。

这是php代码片段

{ "_id" : 1, "keyword" : "24", "found" : 1, "created_at" : "2018-02-27 18:49:07" }
{ "_id" : 2, "keyword" : "100", "found" : 1, "created_at" : "2018-02-27 18:49:10" }
{ "_id" : 3, "keyword" : "15032040", "found" : 1, "created_at" : "2018-02-27 18:49:42" }
{ "_id" : 4, "keyword" : "100", "found" : 1, "created_at" : "2018-02-27 18:49:55" }

当$ docCount为2时,它会提供以下2个数据。

$result = $collection->aggregate([
    ['$match' => ['found' => ['$ne' => 0]]],
    ['$group' => ['_id' => ['keyword' => '$keyword']]],
    ['$sort' => ['created_id' => -1] ],
    ['$limit' => (int) $docCount],
    ['$project' => ['keyword' => '$_id.keyword']]

]);

而我期待结果如下

{
    "_id": {
        "keyword": "15032040"
    },
    "keyword": "15032040"
},
{
    "_id": {
        "keyword": "100"
    },
    "keyword": "100"
}

这里缺少什么?没有组排序工作正常。

3 个答案:

答案 0 :(得分:2)

由于 $group 管道步骤,您正在对从管道中删除的不存在字段进行排序。理想情况下,您希望在 $group 阶段之前进行排序,然后在该组中创建一个有序文档列表,然后您可以 $slice $unwind 进一步深入管道。

请考虑运行以下聚合操作:

$result = $collection->aggregate([
    ['$match' => ['found' => ['$ne' => 0]]],
    ['$sort' => ['created_at' => -1 ]],
    ['$group' => [
        '_id' => null,
        'keywords' => ['$addToSet' => '$keyword']
    ]],
    ['$project' => [
        'keyword' => ['$slice' => ['$keywords', (int) $docCount]]
    ]],
    ['$unwind' => '$keyword']
])

注意

虽然$addToSet仅确保没有重复项添加到集合中并且不会影响现有的重复元素,但它不保证修改集中元素的特定排序。

答案 1 :(得分:1)

您可以使用以下聚合。

$result = $collection->aggregate([
    ['$match' => ['found' => ['$ne' => 0]]],
    ['$sort' => ['created_at' => -1 ]],
    ['$group' => [
        '_id' => '$keyword',
        'created_at' => ['$push' => '$created_at']
    ]],
    ['$addFields' => ['created_at' => ['$arrayElemAt' => ['$created_at', 0]]]],
    ['$sort' => ['created_at' => -1 ]],
    ['$limit' => (int) $docCount]
])

答案 2 :(得分:0)

虽然排序和小组并没有为我合作。我使用php的array_unique函数解决了这个问题。

完整的解决方案:

   $docCount = $this->params()->fromQuery('count');
   $storeId = (string) $this->params()->fromQuery('store_id');
   $collection = new \MongoDB\Collection($this->getManager(), $this->db, $this->searchAnalytics);
    $result = $collection->aggregate([
        ['$match' => ['store_id' => $storeId, 'found' => ['$ne' => 0]]],
        ['$sort' => ['created_at' => -1] ]
    ]);
    $array = $result->toArray();
    $arr = array_column($array, 'keyword');
    $unique = array_unique($arr);
    $limited = array_splice($unique, 0, (int)$docCount);