spring-data-mongodb
spring-data-mongodb copied to clipboard
Exclude projection doesn't working [DATAMONGO-2582]
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
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}}"))
)
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")