Reputation: 2298
I've following documents in search_analytics collection
{ "_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" }
Now I want to get unique search keywords ordered by recently created document at top.
Here is the php code snippet
$result = $collection->aggregate([
['$match' => ['found' => ['$ne' => 0]]],
['$group' => ['_id' => ['keyword' => '$keyword']]],
['$sort' => ['created_id' => -1] ],
['$limit' => (int) $docCount],
['$project' => ['keyword' => '$_id.keyword']]
]);
Which gives following 2 data's when $docCount is 2.
{
"_id": {
"keyword": "15032040"
},
"keyword": "15032040"
},
{
"_id": {
"keyword": "100"
},
"keyword": "100"
}
Whereas I was expecting result as following
{
"_id": {
"keyword": "100"
},
"keyword": "100"
},
{
"_id": {
"keyword": "15032040"
},
"keyword": "15032040"
}
What is missing here? Without group sorting is working fine.
Upvotes: 0
Views: 965
Reputation: 75944
You can use below aggregation.
$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]
])
Upvotes: 1
Reputation: 2298
Though sort and group didn't work together for me. I've solved it using php's array_unique
function.
Complete solution:
$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);
Upvotes: 0
Reputation: 103375
You are sorting on a non-existing field which is removed from the pipeline because of the $group
pipeline step. You ideally want to sort before the $group
stage and then create a list of ordered documents within the group which you can then $slice
and $unwind
further down the pipeline.
Consider running the following aggregate operation instead:
$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']
])
NOTE
While $addToSet
only ensures that there are no duplicate items added to the set and does not affect existing duplicate elements, it does not guarantee a particular ordering of elements in the modified set.
Upvotes: 2