We have a document collection that has varying attributes, lets just call them Entities. Currently we are using Spring Data Mongo Aggregation API to build up our aggregation. Essentially, this is what we are doing:
public class EntityRepository<Entity, String> extends SimpleMongoRepository {
public Page<Entity> findEntities(Pageable pageable, Map<String, Pattern> filters) {
// ... handle empty/null filters and paging
// build up criteria from provided filters
Criteria criteria = new Criteria()
for (Entry<String, Pattern> filter : filters.entrySet()) {
criteria = criteria.and(filter.getKey).regex(filter.getValue);
}
Aggregation aggregation = Aggregation.newAggregation(
match(criteria),
sort(sort),
skip(pageable.getOffset()),
limit(pageable.getPageSize())
);
// ... run aggregation using the MongoOperations
// ... return using PageableExecutionUtils
}
}
Unfortunately we cannot know ahead of time what filters may be coming in. Therefore the query would have to be dynamic.
What I would like to have is the following. Is this even possible? I would imagine it would have to iterate through the map of filters param.
public interface EntityRepository<Entity, String> extends MongoRepository {
// TODO have a match conditional for each key / value pair in filters param
@Aggregation(pipeline = {
"{ $match : { $and: [] } } "
})
@Meta(allowDiskUse = true)
public Page<Entity> findEntities(Pageable pageable, Map<String, Pattern> filters);
}
2
Answers
Use MongoTemplate or MongoOperations instead of aggregation annotation.
Inject one of them and make your queries with your filters map.
Yes, it is possible to dynamically generate the $match stage in your aggregation pipeline based on the keys and values in the filters parameter. You can achieve this by using the AggregationSpELExpression annotation in Spring Data MongoDB.
Here’s an example of how you can modify your EntityRepository interface:
And then, in your implementation, you can dynamically create the $match criteria using the provided filters map: