问题描述
前几天接到一个需求,提供一个查询多设备最后一次的发送GPS的信息,数据是存在MongoDB里面的,每个月的数据都会新建一个collection来存,所以有时候有些设备在当月没有数据的话,需要去查询前一个月的数据返回,所以这里需要一个递归的算法。我原本以为这是一个蛮简单的需求,直接用MongoDB的聚合管道技术的match以及group函数就能轻松解决,我的想法是:
- 首先使用match函数筛选所有需要查询的设备GPS信息
- 对查询的数据按照记录时间进行倒序排序
- 使用group函数对数据进行设备的分类
- MongoDB使用group之后会把$_id设置为group的那个字段,很郁闷(# ̄~ ̄#),我又不能改实体类随便映射到某个字段,所以只能在后面再做一些操作
下面是使用聚合函数的代码。
private List<GpsMiniFullData> findLastList(List<String> guids, Long time, int count,
final List<GpsMiniFullData> gpsMiniFullDataList) {
if (CollectionUtils.isEmpty(guids) || count == getSearchDepth()) {
return gpsMiniFullDataList;
}
//拼装查询条件。
Criteria criteria = Criteria.where(FieldConstants.GUID).in(guids)
.and(FieldConstants.GPSTIME).lt(time).andOperator(createValidFilter(true));
//根据guid分组,按时间倒序排序之后取第一条数据。
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(criteria),
Aggregation.sort(new Sort(new Sort.Order(Direction.ASC, FieldConstants.GUID),
new Sort.Order(Direction.DESC, FieldConstants.GPSTIME))),
Aggregation.group(FieldConstants.GUID)
.first(FieldConstants.ID).as("id")
...
.first(FieldConstants.LOCATION).as(FieldConstants.LOCATION)
);
//请求mongo获取结果
AggregationResults<DBObject