基于嵌套数组字段的最后一个元素的Spring数据MongoDb查询

时间:2019-10-25 23:02:38

标签: mongodb spring-boot spring-data spring-data-mongodb

我有以下数据(汽车):

[
    {
        "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,我想查询检索所有 Cars ,其中最后一个项目的 scheduled_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();

感谢任何帮助建议。

谢谢

1 个答案:

答案 0 :(得分:2)

此mongo聚合检索服务数组中最后一项的schedule_date_time在特定日期范围之间的所有Car。

$stateData = (array)json_decode(fread($file, filesize(public_path('india_state_city1.json'))));

我试图用spring-data-mongodb编写它,但是没有运气。

它们尚不支持 [{ $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') } } }] ,请参阅here

从2.2.0版开始,spring-data-mongodb包含Aggregation Repository Methods

上面的查询应该是

$addFields

此方法记录此查询

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

日期参数解析不正确。我没有花很多时间使它工作。

如果您想要汽车ID,则可以使用。

[{ "$addFields" : { "last" : { "$arrayElemAt" : ["$services", -1]}}}, { "$match" : { "last.scheduled_date_time" : { "$gte" : "$2019-11-03T03:00:00Z", "$lt" : "$2019-11-05T03:00:00Z"}}}]

查询日志

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());

    }