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

2exbekwf  于 2022-12-10  发布在  Spring
关注(0)|答案(4)|浏览(357)

我收藏了这样的文件:

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

并且我希望显示重叠给定百分比(50%)的文档,间隔为(startInterval = 10,endInterval = 90)。
我用下面的公式计算重叠部分:

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

在此范例中:最小值(80,90)-最大值(20,10)/(90-10)=(80-20)/80 = 0.75 --〉75%则会显示此文件,因为75%大于50%
我用mongo shell将这个公式表示为:

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

       $gt: [

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

其中
重叠= 0.5,开始间隔= 10,结束间隔= 90
在mongo shell中工作得很好。
我要求用Spring Data Criteria来计算这个值,因为我在mongo shell中使用的$expr功能仍然要在Spring Data Mongo中实现。目前我使用的是Sping Boot 2.0.0、Spring Data MongoDb 2.0.5和mongodb 3.6。
非常感谢你的时间。

yqhsw0fo

yqhsw0fo1#

添加对$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));

您甚至可以将现有的Criteria与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));
7gcisfzg

7gcisfzg2#

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

其中,RedactAggregationOperation是

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

hi3rlvi23#

正如您提到的,Spring Data 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;
}

正如您所看到的,字段Map工作正常。
使用的Spring Data Mongo工件为org.springframework:data.spring-data-mongodb:2.1.5.RELEASE

juud5qan

juud5qan4#

在spring-data-mongodb库中对$expr运算符的支持仍然不存在。但是有一个使用MongoTemplate来解决这个问题的解决方案-
Aggregation.match()提供了一个重载方法,该方法接受AggregationExpression作为参数。此方法可用于使用$expr运算符为$match聚合管道创建查询,如下所示-

$match运算子的AggregationExpression使用范例-

Aggregation aggregationQuery = Aggregation.newAggregation(Aggregation.match(AggregationExpression.from(MongoExpression.create("'$expr': { '$gte': [ '$foo', '$bar'] }"))));
mongoTemplate.aggregate(aggregationQuery, Entity.class);

以上代码相当于query -

db.collection.aggregate([{"$match": {"$expr": {"$gte: ["$foo", "$bar"]}}}]);

相关问题