mongodb - 基于嵌套数组字段的最后一个元素的Spring数据MongoDb查询
问题描述
我有以下数据(Cars):
[
{
"make" : “Ferrari”,
"model" : “F40",
"services" : [
{
"type" : "FULL",
“date_time" : ISODate("2019-10-31T09:00:00.000Z"),
},
{
"type" : "FULL",
"scheduled_date_time" : ISODate("2019-11-04T09:00:00.000Z"),
}
],
},
{
"make" : "BMW",
"model" : “M3",
"services" : [
{
"type" : "FULL",
"scheduled_date_time" : ISODate("2019-10-31T09:00:00.000Z"),
},
{
"type" : "FULL",
“scheduled_date_time" : ISODate("2019-11-04T09:00:00.000Z"),
}
],
}
]
使用 Spring 数据 MongoDb 我想要一个查询来检索服务数组中最后一项的schedule_date_time在某个日期范围之间的所有汽车。
我之前在使用 services 数组中的第一项时使用的查询如下:
mongoTemplate.find(Query.query(
where("services.0.scheduled_date_time").gte(fromDate)
.andOperator(
where("services.0.scheduled_date_time").lt(toDate))),
Car.class);
请注意 0 索引,因为它是第一个而不是最后一个(对于我当前的要求)。
我认为使用聚合和投影.arrayElementAt(-1)
可以解决问题,但我还没有完全发挥作用。我目前的努力是:
Aggregation agg = newAggregation(
project().and("services").arrayElementAt(-1).as("currentService"),
match(where("currentService.scheduled_date_time").gte(fromDate)
.andOperator(where("currentService.scheduled_date_time").lt(toDate)))
);
AggregationResults<Car> results = mongoTemplate.aggregate(agg, Car.class, Car.class);
return results.getMappedResults();
任何帮助建议表示赞赏。
谢谢,
解决方案
此 mongo 聚合检索所有 Cars,其中 services 数组中最后一项的 schedule_date_time 位于特定日期范围之间。
[{
$addFields: {
last: {
$arrayElemAt: [
'$services',
-1
]
}
}
}, {
$match: {
'last.scheduled_date_time': {
$gte: ISODate('2019-10-26T04:06:27.307Z'),
$lt: ISODate('2019-12-15T04:06:27.319Z')
}
}
}]
我试图在没有运气的情况下在 spring-data-mongodb 中编写它。
他们还不支持$addFields
,请参见此处。
由于版本 2.2.0 RELEASE spring-data-mongodb 包括聚合存储库方法
上面的查询应该是
interface CarRepository extends MongoRepository<Car, String> {
@Aggregation(pipeline = {
"{ $addFields : { last:{ $arrayElemAt: [$services,-1] }} }",
"{ $match: { 'last.scheduled_date_time' : { $gte : '$?0', $lt: '$?1' } } }"
})
List<Car> getCarsWithLastServiceDateBetween(LocalDateTime start, LocalDateTime end);
}
此方法记录此查询
[{ "$addFields" : { "last" : { "$arrayElemAt" : ["$services", -1]}}}, { "$match" : { "last.scheduled_date_time" : { "$gte" : "$2019-11-03T03:00:00Z", "$lt" : "$2019-11-05T03:00:00Z"}}}]
日期参数解析不正确。我没有花太多时间让它工作。
如果你想要汽车 ID,这可以工作。
public List<String> getCarsIdWithServicesDateBetween(LocalDateTime start, LocalDateTime end) {
return template.aggregate(newAggregation(
unwind("services"),
group("id").last("services.date").as("date"),
match(where("date").gte(start).lt(end))
), Car.class, Car.class)
.getMappedResults().stream()
.map(Car::getId)
.collect(Collectors.toList());
}
查询日志
[{ "$unwind" : "$services"}, { "$group" : { "_id" : "$_id", "date" : { "$last" : "$services.scheduled_date_time"}}}, { "$match" : { "date" : { "$gte" : { "$date" : 1572750000000}, "$lt" : { "$date" : 1572922800000}}}}]
推荐阅读
- python - Numpy矢量化元素是元组
- javascript - Nextjs router.push 在第一次点击时页面转换缓慢
- sql - 无法在 oracle 11g 中运行大表连接
- neo4j - Neo4j:如何使数据库重新联机
- java - 使用 Java 和 MySQL 更改密码代码错误
- git - 如何获得在另一台机器上提交的提交?
- firebase - 没有为类型“对象”定义运算符“[]”?功能()'。尝试定义运算符'[]'
- mysql - 导出mysql表以导入另一个数据库的合适格式
- c# - “在解码自定义属性时无法加载类型:(null)”是什么意思?
- python - python opencv网络摄像头不显示任何内容