KeeperOfTheSevenKeys
KeeperOfTheSevenKeys

Reputation: 69

MongoDB filter by retrieved value in group

I have this collection in MongoDB:

[
  { _id: "...", "project": 244, "scanner": "sonarqube", "version": 1 },
  { _id: "...", "project": 244, "scanner": "sonarqube", "version": 2 },
  { _id: "...", "project": 244, "scanner": "sonarqube", "version": 2 },
  { _id: "...", "project": 244, "scanner": "shellcheck", "version": 1 },
  { _id: "...", "project": 244, "scanner": "shellcheck", "version": 2 },
  { _id: "...", "project": 244, "scanner": "shellcheck", "version": 3 },
  { _id: "...", "project": 244, "scanner": "powershell", "version": 2 },
  { _id: "...", "project": 244, "scanner": "powershell", "version": 3 },
  { _id: "...", "project": 244, "scanner": "powershell", "version": 4 },
  { _id: "...", "project": 244, "scanner": "powershell", "version": 4 }
]

I would like to return the number of items, grouped by scanner, with the latest (highest) version:

{ scanner: "sonarqube", count: 2 }, // All items with sonarqube and version: 2
{ scanner: "shellcheck", count: 1 }, // All items with shellcheck and version: 3
{ scanner: "powershell", count: 2 } // All items with powershell and version: 4

So far, I came out with this:

db.getCollection("vulnerabilities").aggregate([
{
    $match: { project_id: 422 }
},
{
    $sort: { version: -1 }
},
{
    $group: {
        _id: "$scanner",
        'count': { $first: "$version"},
    }
}
])

This returns the latest (highest) version for each group:

sonarqube  | 2 |
shellcheck | 3 |
powershell | 4 |

Now, I need to tell Mongo:

Any ideas, suggestion?

Thanks

Upvotes: 0

Views: 446

Answers (2)

Saravana
Saravana

Reputation: 12817

You can use $max in the $group stage

db.test.aggregate([ 
    {$group : {_id : "$scanner", count : {$sum : 1}, version : {$max : "$version"}}}
])

or you can $sort by version and use $first

db.test.aggregate([
    {$sort : {version: -1}}, 
    {$group : {_id : "$scanner", count : {$sum : 1}, version : {$first : "$version"}}}
])

Upvotes: 0

Joe
Joe

Reputation: 28356

The simplest way would be to get the count first, before sorting by version, perhaps:

db.getCollection("vulnerabilities").aggregate([
{
    $match: { project_id: 422 }
},
{   
    $group:{
       _id: { scanner: "$scanner", version: "$version"},
       count: { $sum: 1 }
    }
},
{
    $sort: { "_id.version": -1 }
},
{
    $group: {
        _id: "$_id.scanner",
        count: { $first: "$count" },
        version: { $first: "$_id.version" }
    }
}
])

Upvotes: 1

Related Questions