spring-data-mongodb icon indicating copy to clipboard operation
spring-data-mongodb copied to clipboard

Exclude projection doesn't working [DATAMONGO-2582]

Open spring-projects-issues opened this issue 4 years ago • 2 comments

Jose Armando de Almeida Neto opened DATAMONGO-2582 and commented

Hi! Recently I had a problem with a MongoDB query that when I'm using the code below to remove unneeded fields, the response doesn't remove that.

 

Criteria offerCriteria = where("xTrackId").is(xTrackId)
        .and("offers.id").is(offerId)
        .and("lastTransaction").is(true)
        .and("dtCreate").gt(LocalDate.now().minusDays(creationDateLimitDays));

if (checkUserProfile)
    offerCriteria.and("xUserId").is(xUserId);

ProjectionOperation removeUnneededFields = project()
        .andExclude("offer.request.header",
                "offers.request.search.segment",
                "offers.request.search.businessItem.brokerageUnion",
                "offers.request.search.businessItem.insurance.brokers",
                "offers.request.search.businessItem.insurance.counterPart",
                "offers.request.search.businessItem.insurance.autos.vehicle",
                "offers.request.search.businessItem.insurance.autos.isNewVehicle",
                "offers.items.compositionTracings",
                "offers.items.package");

AggregationResults<Document> result = mongoTemplate.aggregate(newAggregation(
        match(offerCriteria),
        unwind("$offers"),
        match(where("offers.id").is(offerId)),
        removeUnneededFields
), offersCollection, Document.class);

To work around this problem, I used the MongoCollection class and I made the query as the default mongo driver:

 

MongoCollection<Document> collection = mongoTemplate.getCollection(offersCollection);

List<Bson> aggregationPipeline = new ArrayList<>(Arrays.asList(
        match(eq("xTrackId", xTrackId)),
        match(eq("lastTransaction", true)),
        match(eq("offers.id", offerId)),
        match(gt("dtCreate", LocalDate.now().minusDays(creationDateLimitDays)))
));

if (checkUserProfile)
    aggregationPipeline.add(match(eq("xUserId", xUserId)));

aggregationPipeline.addAll(Arrays.asList(
        unwind("$offers"),
        match(eq("offers.id", offerId)),
        project(exclude("offers.request.header",
                "offers.request.search.segment",
                "offers.request.search.businessItem.brokerageUnion",
                "offers.request.search.businessItem.insurance.brokers",
                "offers.request.search.businessItem.insurance.counterPart",
                "offers.request.search.businessItem.insurance.autos.vehicle",
                "offers.request.search.businessItem.insurance.autos.isNewVehicle",
                "offers.items.compositionTracings",
                "offers.items.package"
        ))
));

I hope it was useful!

 

 


No further details from DATAMONGO-2582

spring-projects-issues avatar Jun 29 '20 18:06 spring-projects-issues

Hi! I stumbled across this Bug today. Just to add some insight, it seems that the constructor of org.springframework.data.mongodb.core.aggregation.Fields.AggregationField strips nested field names up until the first dot. I have no idea whats the reason for this though. This also results in wrong fields being excluded if the nested document has keys with the same name as the root document. From:

{
  "a": "a",
  "nested": {
    "a": "a"
  }
}

the pipeline

Aggregation.project().andExclude("nested.a")

will actually result in

{
  "nested": {
    "a": "a"
  }
}

I am currently working around this by extending AggregationOperation to use it with a raw json query.

class CustomJsonAggregation(
  private val jsonOperation: String
) : AggregationOperation {

  override fun toDocument(context: AggregationOperationContext): Document {
    return context.getMappedObject(Document.parse(jsonOperation))
  }
}

Then you can use it as a usual pipeline step:

Aggregation.newAggregation(
  CustomJsonAggregation("{'\$project': {'nested.a': 0}}"))
)

cgoege avatar May 31 '21 15:05 cgoege

I think there is a bug here. I have a nested property with key data.metadata.rawSamplingDate And i'm forced to prefix my exclusion with . for it to work. Working :

project().andExclude(".data.metadata.rawSamplingDate")

Not working (because data is removed in the query):

project().andExclude("data.metadata.rawSamplingDate")

Flowwwww avatar May 25 '23 07:05 Flowwwww