按照数组的最后一个元素排序MongoDB

3
我将尝试将文档按最后交互时间排序。meta_data.access_times是一个数组,每当用户进行交互时,就会更新一次,并将新的日期对象附加到数组的最后一个元素中。有没有办法按照数组的最后一个元素进行排序?
尝试1:
private Aggregation makeQuery(String userId) {
     return newAggregation(
          match(Criteria.where("user_id").is(userId)),
          sort(Sort.Direction.DESC, "$meta_data.access_times"),
          group(Fields.fields().and("first_name", "$meta_data.user_data.first_name").and("last_name", "$meta_data.user_data.last_name").and("profile_pic", "$meta_data.user_data.profile_pic").and("user_id", "$user_id").and("access_times", "$meta_data.access_times"))
      );
    }

尝试二:
 private Aggregation makeQuery(String userId) {
        return newAggregation(
            match(Criteria.where("user_id").is(user_id)),
            group(Fields.fields().and("first_name", "$meta_data.user_data.first_name").and("last_name", "$meta_data.user_data.last_name").and("profile_pic", "$meta_data.user_data.profile_pic").and("user_id", "$user_id")).max("$meta_data.access_times").as("access_time"),
            sort(Sort.Direction.DESC, "access_time")
        );
    }

文档中的示例元数据数组

"meta_data" : { "access_times" : [ 
            ISODate("2017-06-20T14:04:14.910Z"), 
            ISODate("2017-06-22T06:27:32.210Z"), 
            ISODate("2017-06-22T06:27:35.326Z"), 
            ISODate("2017-06-22T06:31:28.048Z"), 
            ISODate("2017-06-22T06:36:19.664Z"), 
            ISODate("2017-06-22T06:37:00.164Z")
        ] }

@NeilLunn 是的! - Januka samaranyake
你期望得到什么输出?group这个词让我感到困惑,因为不清楚期望得到什么结果,尤其是它不是有效的。如果您能展示两三个完整的文档以及您期望的查询结果,那将更容易理解。日期部分我已经理解了。 - Neil Lunn
我的工作是按照最后交互时间对文档进行排序,并分组特定字段(“first_name”,“last_name”,“profile_pic”,“user_id”,“labels”,“access_times”),这些字段都包含在每个文档中。每个用户都有特定的文档。 - Januka samaranyake
你第一次尝试时遇到了什么问题?你能添加一些可以重现情景的文档吗?另外,你期望得到什么输出? - s7vr
我认为我理解了问题,但是第一个查询应该按预期工作。因此,你真的需要添加一些文档到问题中,在运行查询时可以演示问题。 - s7vr
显示剩余4条评论
2个回答

2

我通过使用$unwind操作解决了这个问题。

 private Aggregation makeQuery(String userId) {
        return newAggregation(
            match(Criteria.where("user_id").is(userId)),
            unwind("$meta_data.access_times"),
            group(Fields.fields().and("first_name", "$meta_data.user_data.first_name").and("last_name", "$meta_data.user_data.last_name").and("profile_pic", "$meta_data.user_data.profile_pic").and("user_id", "$user_id")).max("$meta_data.access_times").as("access_time"),
            sort(Sort.Direction.DESC, "access_time")
        );
    }

1

当您不知道要推送的元素是否有序(例如,正在推送他的分数的用户...),您可以使用$push和$sort来获得有序数组,然后只需按“find({userId:yourUseId}.sort("metadata.access_time.0":-1)进行排序。

这个解决方案假设您的数组在创建/更新时使用$sort排序:LINK

当您确定Push不需要排序时(例如,您正在为该用户推送Access_Date),您可以使用$operator(tnx Erdenezul)进行$push和void $sort。 LINK

理论上,如果find()仅获取少量文档,则不需要对数组“access_time”进行索引。否则,您只需添加一个索引{"metadata.access_time.0": -1}即可。

祝好运!


1
在0号位置使用push操作将最新的访问添加进去会很好。 - Erdenezul
@Erdenezul,你认为这不是一个可行的解决方案吗? - Daniele Tassone
1
为了避免排序,将最新的元素推到索引0更有效。 - Erdenezul
@Erdenezul,你说得对,$position可以使用,但我刚刚发布了一个适用于任何情况的通用解决方案。 - Daniele Tassone
@Erdenezul 让我知道。 - Daniele Tassone
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接