Spring Data mongodb聚合框架:project()中的ConditionalOperators进行中位数计算

Posted

技术标签:

【中文标题】Spring Data mongodb聚合框架:project()中的ConditionalOperators进行中位数计算【英文标题】:Spring Data mongodb aggregation framework: ConditionalOperators in project() for median calculation 【发布时间】:2018-09-25 05:22:32 【问题描述】:

在使用 Spring Data 2.0 的示例项目中,我试图计算具有以下格式的文档的温度中值:

  
   "_id":ObjectId("5ad28e92e284e00bbc0a9479"),
   "deviceId":"myId",
   "time":   ISODate("2018-04-21T23:28:18.632   Z"),
   "temperature":10,
   "_class":"com.github.paizo.monitorapi.model.Refrigerator"

从here 我抓取一个聚合管道来计算我转换为以下 Spring Data 聚合的中值:

final Aggregation aggregation = newAggregation(
        match(
                Criteria.where(DEVICE_ID_FIELD).is(deviceId)
        ),
        group().count().as("count").push(sensorValueField).as("values"),
        unwind("values"),
        sort(Sort.Direction.ASC, "values"),
        project("count", "values")
                .andExpression("(count) / 2").as("midpoint"),
        project("count", "values", "midpoint")
                .and(floor).as("low")
                .and(ceil).as("high"),
        group()
                .push("values").as("values")
                .avg("high").as("high")
                .avg("low").as("low"),
        project()
                .and(beginValue).as("beginValue")
                .and(endValue).as("endValue"),
        //FIXME if ODD => v1 == v2 then return v1 else v1 != v2 => return average(v1,v2)
        project().and(
                ConditionalOperators.when(Criteria.where("beginValue").ne("endValue"))
                    .then("beginValue")
                    .otherwiseValueOf("(beginValue + endValue) / 2")
        )
);

我试图在最后一个project() 中进行最终值检查的计算中可能出现的错误的一部分。 无论我在ConditionalOperators.when() 中写什么,生成的项目都是空的

  
   "aggregate":"refrigerator",
   "pipeline":[  
        
         "$match":  
            "deviceId":"myId"
         
      ,
        
         "$group":  
            "_id":null,
            "count":  
               "$sum":1
            ,
            "values":  
               "$push":"$temperature"
            
         
      ,
        
         "$unwind":"$values"
      ,
        
         "$sort":  
            "values":1
         
      ,
        
         "$project":  
            "count":1,
            "values":1,
            "midpoint":  
               "$divide":[  
                  "$count",
                  2
               ]
            
         
      ,
        
         "$project":  
            "count":1,
            "values":1,
            "midpoint":1,
            "low":  
               "$floor":"$midpoint"
            ,
            "high":  
               "$ceil":"$midpoint"
            
         
      ,
        
         "$group":  
            "_id":null,
            "values":  
               "$push":"$values"
            ,
            "high":  
               "$avg":"$high"
            ,
            "low":  
               "$avg":"$low"
            
         
      ,
        
         "$project":  
            "beginValue":  
               "$arrayElemAt":[  
                  "$values",
                  "$low"
               ]
            ,
            "endValue":  
               "$arrayElemAt":[  
                  "$values",
                  "$high"
               ]
            
         
      ,
        
         "$project":  

         
      
   ],
   "cursor":  
      "batchSize":2147483647
   

导致错误的原因:

org.springframework.data.mongodb.UncategorizedMongoDbException: Command failed with error 40177: 'Invalid $project :: caused by :: specification must have at least one field' on server localhost:27017. The full response is  "ok" : 0.0, "errmsg" : "Invalid $project :: caused by :: specification must have at least one field", "code" : 40177, "codeName" : "Location40177" ; nested exception is com.mongodb.MongoCommandException: Command failed with error 40177: 'Invalid $project :: caused by :: specification must have at least one field' on server localhost:27017. The full response is  "ok" : 0.0, "errmsg" : "Invalid $project :: caused by :: specification must have at least one field", "code" : 40177, "codeName" : "Location40177" 

我对最后一个project() 做错了什么?是 Spring 数据问题吗?

【问题讨论】:

【参考方案1】:

回答我自己的问题,也许它可以帮助别人。

原来$project没有生成是因为project.and(...)后面缺少as()

以下示例为条件运算符正确生成$project

            project().and(ConditionalOperators.when(Criteria.where("beginValue").ne("endValue"))
                    .then("beginValue")
                    .otherwiseValueOf("(beginValue + endValue) / 2")).as("lowViewsQuestion")

【讨论】:

以上是关于Spring Data mongodb聚合框架:project()中的ConditionalOperators进行中位数计算的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data MongoDB:如何用 Spring Aggregation 描述聚合 $merge?

无法使用 Spring Data JPA 执行聚合函数并获取结果

使用 mongoTemplate 在 spring-data-mongo Java 中进行 Mongo 聚合查询

将 mongodb 聚合查询翻译成 Java/Kotlin Spring Data

spring data中如何编写Replace root和merge对象聚合操作

Spring Data MongoDB聚合分页查询中SkipOPeration和LimitOperation的位置