Search code examples
spring-data-mongodb

Why MongoDB aggregation is rewritten by Spring Data in a wrong way?


There is a collection

{
  "field": {
    "nested": 0
  }
}

It is necessary to get a sum of nested fields. As direct operation like below is not allowed

{
  "$group": {
    "_id": null,
    "field.nested": {
      "$sum": "$field.nested"
    }
  }
}

It is done by the following aggregation with pre and post projection.

[
  {
    "$project": {
      "fieldNested": "$field.nested"
    }
  },
  {
    "$group": {
      "_id": null,
      "fieldNested": {
        "$sum": "$fieldNested"
      }
    }
  },
  {
    "$project": {
      "total": {
        "field" : {
          "nested" : "$fieldNested"
        }
      }
    }
  }
]

And it works correctly in the Mongo DB shell. The problem comes with using this aggregation in Spring Data in a json format. For example,

@Repository
public interface Sample extends MongoRepository<InData, String> {

    @Aggregation({
            "" +
                    "{" +
                    "  '$project': {" +
                    "    'fieldNested': '$field.nested'" +
                    "  }" +
                    "}",
            "" +
                    "{" +
                    "  '$group': {" +
                    "    '_id': null," +
                    "    'fieldNested': {" +
                    "      '$sum': '$fieldNested'" +
                    "    }" +
                    "  }" +
                    "}",
            "" +
                    "{" +
                    "  '$project': {" +
                    "    'total': {" +
                    "      'field': {" +
                    "        'nested': '$fieldNested'" +
                    "      }" +
                    "    }" +
                    "  }" +
                    "}"
    })
    List<OutData> aggregateBy();

}

Somehow this json is rewritten by Spring Data so that the pipelines sent to the Mongo looks like the following

[
  {
    "$project": {
      "field.nested": "$field.nested"
    }
  },
  {
    "$group": {
      "_id": null,
      "field.nested": {
        "$sum": "$fieldNested"
      }
    }
  },
  {
    "$project": {
      "total": {
        "field" : {
          "nested" : "$fieldNested"
        }
      }
    }
  }
]

fieldNested is replaced by field.nested. As a result the aggregation fails.

Why it happens? Is there any way to avoid this rewrite by Spring Data for MongoDB (Spring Boot 2.2.13.RELEASE, MongoDB 3.6.8)?


Solution

  • Spring Data MongoDB is converting fieldNested to field.nested because your InData class & its collection is having fields in that hierarchy. If you want to project that nested field using @Aggregation, then project it using any other name that is not part of your InData class & its collection's fields so Spring Data won't convert it.