首页 > 解决方案 > Spring Data mongoDB:如何根据日期为每个名称获取一个文档

问题描述

我有一个要执行的 mongoDB 请求,最初对我来说听起来很容易,但让我汗流浃背,结果我不太相信。我搜索了很多类似的问题,但没有一个真正满足我的需求。我正在为我的后端使用 Spring Boot 框架。目标相当简单。我在数据库中有一组文档,如下例所示:

[{“name” : “Bob”,
“contract” : false,
”ranking” : 3,
“timestamp”: 1606867200},
{“name” : “Bob”,
“contract” : true,
”ranking” : 5,
“timestamp”: 1606953600},
{“name” : “Roger”,
“contract” : true,
”ranking” : 25,
“timestamp”: 1607040000},
{“name” : “Bob”,
“contract” : true,
”ranking” : 5,
“timestamp”: 1607040000}]

我想为每个唯一名称获取一个文档,其中时间戳(即以纪元毫秒格式表示的日期)最高(即最新日期)。所以在上面的例子中我会有两个结果:

[{“name” : “Roger”,
“contract” : true,
”ranking” : 25,
“timestamp”: 1607040000},
{“name” : “Bob”,
“contract” : true,
”ranking” : 5,
“timestamp”: 1607040000}]

为此,我找到的唯一解决方案是使用聚合。这可以在 Spring 中使用 mongoTemplate 或在我的情况下使用聚合存储库方法来完成,该方法工作正常,也请参见此处了解详细信息

我想要的是在 mongo 中为每个名称获取一个文档,为每个名称选择的文档是具有最大时间戳的文档。据我了解,这不是直接可行的。我们必须使用聚合管道创建一个新文档,告诉他根据名称进行分组_id: '$name'并选择最高时间戳:timestamp: {$max: '$timestamp'}。但是,这样做会创建一个只有两个字段的文档:_ID 和时间戳,我在 Spring 中的 POJO 需要(名称、合同、排名、时间戳)。我发现添加其余字段的唯一方法是这样做:

String myAggregation = "{ $group: {" +
    "_id: '$name'," +
    "name: {$first: '$name'}," +
    "contract: {$first: '$contract'}," +
    "ranking: {$first: '$ranking'}," +
    "timestamp: {$max: '$timestamp'}," +
    "}}";
// find the latest scan status for each individual UID
@Aggregation(myAggregation)
List<HotlistStatusEntity> findLastStatusOfEachName();

但我觉得在某些情况下,这可能会导致不希望的结果,因为 $first 从文档中选择的值与 $max 选择的值不同。我缺乏一种清晰的方式来解释我的担忧,但在做我所做的事情时,我不会获取现有文档的列表,而是通过选择“这里和那里”的值来重新创建文档。尽管我的测试从未导致意外结果,但我仍然对此没有信心。那么是否有更安全或更清洁的方式来实现这一目标?在此先感谢您的帮助。

标签: springmongodbaggregation-framework

解决方案


推荐阅读