Search code examples
javamongodbaggregation-frameworkmongodb-javamongodb-java-3.3.0

Mongo db java driver query convert


I have the following data structure

[{
    "id": "1c7bbebd-bc3d-4352-9ac0-98c01d13189d",
    "version": 0,
    "groups": [
        {
            "internalName": "Admin group",
            "fields": [
                {
                    "internalName": "Is verified",
                    "uiProperties": {
                        "isShow": true
                    }
                },
                {
                    "internalName": "Hide",
                    "uiProperties": {
                        "isHide": false
                    }
                },
                ...
            ]
        },
        ...
    ]     
},
{
    "id": "2b7bbebd-bc3d-4352-9ac0-98c01d13189d",
    "version": 0,
    "groups": [
        {
            "internalName": "User group",
            "fields": [
                {
                    "internalName": "Is verified",
                    "uiProperties": {
                        "isShow": true
                    }
                },
                {
                    "internalName": "Blocked",
                    "uiProperties": {
                        "isBlocked": true
                    }
                },
                ...
            ]
        },
        ...
    ]     
},
...
]

Internal names of the fields can be repeated. I want to group by group.field.internalName and cut the array(for pagination) and get the output like:

{
"totalCount": 3,
"items": [
    {
         "internalName": "Blocked"
    },
    {
         "internalName": "Hide"
    },
    {
         "internalName": "Is verified"
    }
]}

I wrote a query that works,

db.layouts.aggregate(
{ 
    $unwind : "$groups" 
},
{ 
    $unwind : "$groups.fields" 
},
{
    $group: {
        "_id" : {
            "internalName" : "$groups.fields.internalName",
        },
        "internalName" : {
            $first : "$groups.fields.internalName"
        }
    }
},
{
    $group: {
        "_id" : null,
        "items" : {
            $push : "$$ROOT"
        },
        "totalCount" : {
            $sum : 1
        }
    }
},
{
    $project: {
        "items" : {
            $slice : [ "$items", 0, 20 ]
        },
        "totalCount": 1
    }
})

but I have the problem of translating it to java api. Notice that i need to use mongoTemplate approach. Here is what i have and where i'm struck

    final List<AggregationOperation> aggregationOperations = new ArrayList<>();
    aggregationOperations.add(unwind("groups"));
    aggregationOperations.add(unwind("groups.fields"));

    aggregationOperations.add(
            group("groups.fields.internalName")
                .first("groups.fields.internalName").as("internalName")
    );

    aggregationOperations.add(
            group()
                 .push("$$ROOT").as("fields")
                 .sum("1").as("totalCount") // ERROR only string ref can be placed, but i need a number?
    );

    aggregationOperations.add(
            project()
                  .andInclude("totalCount")
                  .and("fields").slice(size, page * size)
    );
    final Aggregation aggregation = newAggregation(aggregationOperations);
    mongoTemplate.aggregate(aggregation, LAYOUTS, FieldLites.class).getMappedResults()

With this query i have the problem with sum(), because i can place only a String ref by api(but need a number) and with project operation - got an exception java.lang.IllegalArgumentException: Invalid reference 'totalCount'!] with root cause

Can you help me with this query translation?


Solution

  • You can use count

    group()
        .push("$$ROOT").as("fields")
        .count().as("totalCount")