Search code examples
springmongodbspring-dataspring-data-mongodb

Spring Data MongoDb - Criteria equivalent to a given query that uses $expr


I have a collection with documents like this:

 {
    "_id" : ObjectId("5a8ec4620cd3c2a4062548ec"),
    "start" : 20,
    "end" : 80
 }

and I want to show the documents that overlap a given percentage (50%) with an interval (startInterval = 10, endInterval = 90).

I calculate the overlaping section with the following formula:

min(end , endInterval) - max(start, startInterval ) / (endInterval - startInterval)

In this example: min(80,90) - max(20,10) / (90-10) = (80-20)/80 = 0.75 --> 75% Then this document will be shown, as 75% is greater than 50%

I expressed this formula in mongo shell as:

db.getCollection('variants').find(
  {
     $expr: {  

       $gt: [

              { 
                $divide: [
                           { 
                             $subtract: [ 
                                          { $min: [ "$end", endInterval ]  }
                                          , 
                                          { $max: [ "$start", startInterval ]  } 
                             ] 
                           }
                           , 
                           { $subtract: [ endInterval, startInterval ] }
                         ] 
              }
             , 
             overlap 
            ]
      }
  }
)

where

overlap = 0.5, startInterval = 10 and endInterval= 90

It works fine in mongo shell.

I'm asking for an equivalent way to calculate this using Spring Data Criteria, since the $expr functionality I used in mongo shell is still to be implemented in Spring Data Mongo. Currently I'm using Spring Boot 2.0.0, Spring Data MongoDb 2.0.5 and mongodb 3.6.

Thanks a lot for your time.


Solution

  • Just in case it is helpful for somebody, I finally solved my problem using $redact.

    String redact = "{\n" + 
                "       \"$redact\": {\n" + 
                "           \"$cond\": [\n" + 
                "               {\n" + 
                "                   \"$gte\": [\n" + 
                "                       {\n" + 
                "                           \"$divide\": [\n" + 
                "                               {\n" + 
                "                                   \"$subtract\": [\n" + 
                "                                       {\n" + 
                "                                           \"$min\": [\n" + 
                "                                               \"$end\",\n" + 
                "                                           "   + endInterval + "\n" + 
                "                                           ]\n" + 
                "                                       },\n" + 
                "                                       {\n" + 
                "                                           \"$max\": [\n" + 
                "                                               \"$start\",\n" + 
                "                                           "   + startInterval + "\n" + 
                "                                           ]\n" + 
                "                                       }\n" + 
                "                                   ]\n" + 
                "                               },\n" + 
                "                               {\n" + 
                "                                   \"$subtract\": [\n" + 
                "                                   "   + endInterval + "\n" + 
                "                                   "   + startInterval + "\n" +  
                "                                   ]\n" + 
                "                               }\n" + 
                "                           ]\n" + 
                "                       },\n" + 
                "                   "   + overlap + "\n" + 
                "                   ]\n" + 
                "               },\n" + 
                "               \"$$KEEP\",\n" + 
                "               \"$$PRUNE\"\n" + 
                "           ]\n" + 
                "       }\n" + 
                "   }";
    
    
        RedactAggregationOperation redactOperation = new RedactAggregationOperation(
                Document.parse(redact)
        );      
    

    where RedactAggregationOperation is

    public class RedactAggregationOperation implements AggregationOperation {
        private Document operation;
    
        public RedactAggregationOperation (Document operation) {
            this.operation = operation;
        }
    
        @Override
        public Document toDocument(AggregationOperationContext context) {
             return context.getMappedObject(operation);
        }
    }