mongodbscalareactivemongoplay-reactivemongo

In Reactivemongo Aggregation Framework, how to specify multiple keys in the group function "Max"?


This is sample data (expireDate is optional):

{"userId":"1","appId":"1","createdDate":10}
{"userId":"1","appId":"1","createdDate":5,"expireDate":30}
{"userId":"1","appId":"1","createdDate":12,"expireDate":20}
{"userId":"1","appId":"1","createdDate":12,"expireDate":5}

This is the aggregation function that I want to translate to reactivemongo aggregation framework:

db.collection_name.aggregate([
{
    $match : {"userId" : "1"} 
},
{
    $group : {
        "_id" : "$appId",
        "docs" : { 
            $max : { 
                "createdDate" : "$createdDate",
                "expireDate" : "$expireDate"
            }
        } 
    }
}
])

To run the aggregation function on the sample data (with mongo shell 3.2.9), the result is:

{ "_id" : "1", "docs" : { "createdDate" : 12, "expireDate" : 20 } }

When I try to convert this aggregation function to reactivemongo, I realize that the group function "Max" only takes one string as parameter, so I don't know how to put both "createdDate" and "expireDate" in it. Here is what I figure out so far:

col.aggregate(
  Match(BSONDocument("userId" -> "1")),
  List(Group(BSONString("$appId"))( "docs" -> Max("createdDate")))
)

Can anybody tell me how to add "expireDate" into "Max" function?
Note that I'm using reactivemongo 0.11, and upgrading to 0.12 is not an option.


Solution

  • You can use reactivemongo.api.commands.AggregationFramework.GroupFunction.apply to create a custom call to a group function. Here is the doc and here is the source where I found it.

    GroupFunction("$max", BSONDocument("createdDate" -> "$createdDate", "expireDate" -> "$expireDate"))
    

    Use this function instead of Max, so your code becomes:

    col.aggregate(
      Match(BSONDocument("userId" -> "1")),
      List(Group(BSONString("$appId"))( "docs" -> GroupFunction("$max", BSONDocument("createdDate" -> "$createdDate", "expireDate" -> "$expireDate"))))
    )
    

    Don't forget to import col.BatchCommands.AggregationFramework.GroupFunction.

    Of course you can define a more generic function which takes any BSONDocument as a parameter, if you want:

    def BetterMax(doc: BSONDocument) = GroupFunction("$max", doc)