Cannot figure out how to do a GROUP BY using the MongoDB Java Sync driver API

Greetings all,

Apologies if this has already been answered somewhere but I’m struggling to find a solution to what should be a very simple GROUP BY requirement using the MongoDB Java Sync Driver.

I am upgrading MongoDB in an aging tech stack from 3.4 to 5.0.13 in order to fully support a Grails 5 upgrade.

Previously this application was using GMongo, which is a Groovy wrapper around the old Mongo Java Driver that allowed you to write native-like queries. It hasn’t been updated since 2016 and doesb’t support the new driver API, hence the need to upgrade.

Anyway I have the following Group stage written in GMongo format which I’m trying to convert to MongoDB Sync Driver API format:

    def shopInfringementsNoPartner(String fromDate, String toDate, Long clientId) {
    Client client = Client.get(clientId)
    
    // GMongo query
    def match = ['date.d'                : [$gte: fromDate, $lte: toDate],
                 'product.cl'            : clientId,
                 'platform.id'         : [$in: client.platforms.id],
                 "shop.inf.${clientId}"  : [$exists: true],
                 "shop.cl_pt.${clientId}": [$exists: false],
                 'product.a'             : true]

    def result = facts().aggregate(
            [$match: match],
            [$group: [_id  : [shop_id: '$shop.id'],  // I think this line is the groupBy
                      count: [$sum: 1],
                      n    : [$first: '$shop.n'],
                      dn   : [$first: '$shop.dn']]]
    ).results()

You can see during the Group stage that there is a groupBy (I think) on “$shop.id”.

I have the following code written in the new Java API:

        // Mongo DB Java Sync Driver API query
        final List<Bson> aggregationPipeline = asList(
            Aggregates.match(Filters.and(Filters.gte("date.d", fromDate), Filters.lte("date.d", toDate))),
            Aggregates.match(Filters.eq("product.cl", clientId)),
            Aggregates.match(Filters.in("platform.id", platformIds)),
            Aggregates.match(Filters.exists("product.cl", true)),
            Aggregates.match(Filters.exists("product.cl", false)),
            Aggregates.match(Filters.eq("product.cl", true)),
            Aggregates.group(null,
                    asList(
                     // not sure what to put here
                        Accumulators.sum("count",1),
                        Accumulators.first("n","$shop.n"),
                        Accumulators.first("dn","$shop.dn")
                    )
            )
    );

And someone suggested that to do a GROUP BY using this API, I would need to do Accumulators.groupBy()

Problem with this suggestion is, there is no such .groupBy() method anywhere in the Java Sync driver API that I can see. I’m actually having a lot of trouble figuring out how to do this one simple thing.

Can anyone explain how I would do a GROUP BY using the new Java API in order to replicate the original GMongo logic?

Can anybody help me please?

Is it just not possible to do a Group By using this API?

I do not use the aggregation’s builders. I prefer to keep my queries in plain JSON format and then use Document.parse(). Mainly because I switch often between Java, node, Compass and mongosh.

But you could try to write your aggregation in Compass and then use the Export feature to get the builders’ version.

But with my little knowledge about builders and 0 knowledge of GMongo, the following looks okay

But

might need to be something like

Aggregates.group("$shop.id"

in order to match

With null you probably group everything together rather than by store.

I also thing that calling Aggregates.match many times will create a lot of $match stage rather than a single one.

Thanks Steeve, I’ll test out a couple of things you have suggested.

As an aside Steeve, when you parse and execute the queries you keep in native JSON format, are you using Java?

Can you give me an example of how you do this please?

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.