Conditional/max mongo 查询使用 spring mongo 模板

Conditional/max mongo queries using spring mongoTemplate

我在 mongodb 集合中有数百条这样的记录:

{
    "city" : "London",
    "eventTime": 1582866000,
    "createdTime": 1582900145,
    "eventDetails: {
        ...
    }
}

这是对应的Eventclass

public class Event {
    private String city;
    private long eventTime;
    private long createdTime;
    private EventDetails eventDetails;

    //getters and setters
}

-eventTime(所有时间值均为本地 epoch/unix 时间)将始终等于一个小时
-createdTime 被用作版本控制(大于 createdTime,此信息的版本更新)
- 不使用 update/upsert 因为我有保留旧信息的用途

我希望能够查询这样的内容:

1) 给定版本时间戳 - return 每个 city 的对象列表(整个对象),每个 eventTime,其中时间戳最接近(floor 或 celing)createdTime
2) 与 1) 相同,但对于 max(createdTime) - 对于每个 city 和每个 eventTime

基本上-每个city,每个eventTime都会有很多重复,因为有多个版本,我只想要我指定的版本,最新版本

我正在尝试使用 mongoTemplate in java (spring mongo) 进行这两个查询 我尝试过 QueryAggregationAggregationOperator.Max 但似乎没有任何效果

Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("city").is(city)),
Aggregation.match(Criteria.where("eventTime").gte(startTime).lte(endTime)),
Aggregation.group("$$ROOT").max("createdTime").as("createdTime")
);
AggregationResults<Event> groupResults = mongoTemplate.aggregate(aggregation, "collection-name", Event.class);
result = groupResults.getMappedResults();

示例数据和预期输出:https://script.google.com/d/1JgOFzdVBGiueYpXT8u-R6AJpbX6FxxtkVwq_NpLraZeS19Pxh6zmnATb/edit?usp=sharing

我也试过在 mongodb shell 中进行这些查询,但也没有成功,它很相似,但不是 returning 我的对象结构想要

db.getCollection('collection-name').aggregate([{$group:{_id : "$$ROOT", createdTime : {$max:"$createdTime"}}}])

最大

db.collection.aggregate([
  {
    $group: {
      _id: {
        city: "$city",
        eventTime: "$eventTime"
      },
      max: {
        $max: "$createdTime"
      },
      data: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $project: {
      max_events: {
        $filter: {
          input: "$data",
          cond: {
            $eq: [
              "$max",
              "$$this.createdTime"
            ]
          }
        }
      }
    }
  },
  {
    $unwind: "$max_events"
  },
  {
    $replaceRoot: {
      newRoot: "$max_events"
    }
  }
])

MongoPlayground

MongoTemplate

import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

Aggregation agg = Aggregation.newAggregation(
    group("city", "eventTime").max("createdTime").as("max").push("$$ROOT").as("data"),
    project().and(new AggregationExpression() {
        @Override
        public Document toDocument(AggregationOperationContext context) {
            return new Document("$filter",
                    new Document("input", "$data")
                         .append("cond", new Document("$eq", Arrays.asList("$max", "$$this.createdTime"))));
        }
    }).as("max_events"),
    unwind("max_events"),
    replaceRoot("max_events")
);

AggregationResults<Event> events = mongoTemplate.aggregate(agg, mongoTemplate.getCollectionName(Event.class), Event.class);

for(Event ev: events) {
    System.out.println(ev);
}

最近

db.collection.aggregate([
  {
    $group: {
      _id: {
        city: "$city",
        eventTime: "$eventTime"
      },
      data: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $project: {
      closest: {
        $reduce: {
          input: "$data",
          initialValue: {
            $arrayElemAt: [
              "$data",
              0
            ]
          },
          in: {
            $cond: [
              {
                $lt: [
                  {
                    $abs: {
                      $subtract: [
                        "$$this.eventTime",
                        "$$this.createdTime"
                      ]
                    }
                  },
                  {
                    $abs: {
                      $subtract: [
                        "$$value.eventTime",
                        "$$value.createdTime"
                      ]
                    }
                  }
                ]
              },
              "$$this",
              "$$value"
            ]
          }
        }
      }
    }
  },
  {
    $unwind: "$closest"
  },
  {
    $replaceRoot: {
      newRoot: "$closest"
    }
  }
])

MongoPlayground

MongoTemplate

Aggregation agg = Aggregation.newAggregation(
    group("city", "eventTime").push("$$ROOT").as("data"),
    project().and(new AggregationExpression() {
        @Override
        public Document toDocument(AggregationOperationContext context) {
            return new Document("$reduce",
                    new Document("input", "$data")
                     .append("initialValue", new Document("$arrayElemAt", Arrays.asList("$data", 0)))
                     .append("in", new Document("$cond", Arrays.asList(
                            new Document("$lt",  Arrays.asList(
                                new Document("$abs", new Document("$subtract", Arrays.asList("$$this.eventTime", "$$this.createdTime"))), 
                                new Document("$abs", new Document("$subtract", Arrays.asList("$$value.eventTime", "$$value.createdTime"))))), 
                            "$$this",
                            "$$value"))));
        }
    }).as("closest"),
    unwind("closest"),
    replaceRoot("closest")
);

AggregationResults<Event> events = mongoTemplate.aggregate(agg, mongoTemplate.getCollectionName(Event.class), Event.class);

for(Event ev: events) {
    System.out.println(ev);
}