Spring 数据 MongoDb - 与使用 $expr 的给定查询等效的条件

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

我有一个 collection 文件是这样的:

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

并且我想显示以一定间隔(startInterval = 10,endInterval = 90)重叠给定百分比 (50%) 的文档。

我用下面的公式计算重叠部分:

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

在这个例子中: 最小值 (80,90) - 最大值 (20,10) / (90-10) = (80-20)/80 = 0.75 --> 75% 然后会显示这个文档,因为75%大于50%

我在mongoshell中将这个公式表示为:

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

       $gt: [

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

哪里

overlap = 0.5,startInterval = 10 和 endInterval= 90

它在 mongo shell.

中工作正常

我要求使用 Spring 数据标准进行计算的等效方法,因为我在 mongo shell 中使用的 $expr 功能仍将在 Spring数据Mongo。 目前我正在使用 Spring Boot 2.0.0,Spring Data MongoDb 2.0.5 和 mongodb 3.6.

非常感谢您的宝贵时间。

以防万一它对某人有帮助,我终于使用 $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)
    );      

其中 Redact AggregationOperation 是

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);
    }
}

正如你所说,Spring数据Mongo目前不支持$expr,所以我必须使用自定义BSON文档,以及MongoTemplate的反射。

public List<Variant> listTest() throws Exception {

    double overlap = 0.5;
    int startInterval = 10;
    int endInterval= 90;

    String jsonQuery = "{$expr:{$gt:[{$divide:[{$subtract:[{$min:[\"$end\","+endInterval+"]},{$max:[\"$start\","+startInterval+"]}]},{$subtract:["+endInterval+","+startInterval+"]}]},"+overlap+"]}}";
    Document query = Document.parse(jsonQuery);

    Method doFind = MongoTemplate.class.getDeclaredMethod("doFind", String.class, Document.class,Document.class,Class.class);
    doFind.setAccessible(true);
    return (List<Variant>) doFind.invoke(mongoTemplate, "variants", query, new Document(), Variant.class);
}

@NoArgsConstructor @Getter @Setter @ToString
public static class Variant{
    int start;
    int end;
}

如您所见,字段映射工作正常。

使用的Spring数据Mongo神器是org.springframework:data.spring-data-mongodb:2.1.5.RELEASE

添加对 $expr 支持的未解决问题:https://github.com/spring-projects/spring-data-mongodb/issues/2750

同时,您可以使用 BasicQuery:

BasicQuery query = new BasicQuery("{ $expr: {'$gt': ['$results.cache.lastHit', '$results.cache.expiration']}}");
return ofNullable(mongoTemplate.findAndModify(query, updateDefinition, XXXX.class));

您甚至可以将现有条件与 BasicQuery 连接起来,使其独占 $expr:

Criteria criteria = Criteria.where("results.cache.cacheUpdateRetriesLeft").gt(4);
BasicQuery query = new BasicQuery("{ $expr: {'$gt': ['$results.cache.lastHit', '$results.cache.expiration']}}");
query.addCriteria(criteria);
return ofNullable(mongoTemplate.findAndModify(query, updateDefinition, XXXX.class));