Spring Data MongoDB聚合涉及Unwind、Match、Sort和group

时间:2021-08-01 17:00:36

I have a collection named User which contains embedded document called Message. The embedded document Message contains array of message object as below :

我有一个名为User的集合,其中包含名为Message的嵌入式文档。嵌入式文档消息包含消息对象数组,如下所示:

{
  "_id" : ObjectId("58e09daa192216e39fd85433"),
  "userId" : "user123",
  "message" : [ 
    {
        "messageId" : "5277941e-9d84-46c3-b927-ef33abbf35f2",
        "dateCreated" : 1491115000,
        "body" : "howdy?",
        "type" : "text"
    }, 
    {
        "messageId" : "c2ce0480-bc0d-4393-89d4-27174d323b98",
        "dateCreated" : 1491119000,
        "body" : "i've problem with my account. can you help?",
        "type" : "text"
    }, 
    {
        "messageId" : "45b2593c-a960-4066-8723-db2531dd8bab",
        "dateCreated" : 1491100000,
        "body" : "this is urgent",
        "type" : "text"
    }
  ]
}

My objective is to sort embedded document Message based on dateCreated key. I need to translate this mongo query into Spring Data MongoDB :

我的目标是基于dateCreated键对嵌入的文档消息进行排序。我需要将这个mongo查询翻译成Spring Data MongoDB:

db.user.aggregate(
  {$unwind: "$message"}, 
  {$match: {userId: "user123"}},
  {$sort: {"message.dateCreated": 1}},
  {$group: {_id: "$_id", "message": {"$push": "$message"}}})

I've tried the following codes but still getting error :

我试过下面的代码,但还是有错误:

AggregationOperation unwind = Aggregation.unwind("message");
AggregationOperation match = Aggregation.match(Criteria.where("userId").in("user123"));
AggregationOperation sort = Aggregation.sort(Direction.ASC, "message.dateCreated");
AggregationOperation group = Aggregation.group("userId", "message");

Aggregation aggregation = Aggregation.newAggregation(unwind, match, sort, group);

AggregationResults<User> groupResults = mongoTemplate.aggregate(aggregation, User.class, User.class);

Error :

错误:

Failed to instantiate [java.util.List]: Specified class is an interface

实例化(java.util失败。指定的类是一个接口

User class :

用户类:

@Document(collection="user")
public class User {

  @Id
  private String id;
  private String userId;
  @Field("message")
  @DBRef
  private List<Message> message;
  //constructor, getter, setter
}

Message class :

信息类:

@Document
public class Message {
  private String messageId;
  private long dateCreated;
  private String body;
  private String type;
  //constructor, getter, setter
}

Hint :

提示:

Based on my research, I'm pretty sure that I need to use GroupOperationBuilder group = Aggregation.group("userId").push("message") but I don't really know how to proceed with this as AggregationResults will not allow me to use it in the mongoTemplate.aggregate()

基于我的研究,我非常确定我需要使用GroupOperationBuilder组= aggreg. group(“userId”).push(“消息”),但是我不知道如何进行这个操作,因为聚合结果将不允许我在mongotemplate .聚合()中使用它。

2 个解决方案

#1


0  

Optimize query will be:

优化查询将:

db.user.aggregate(
 {$match: {userId: "user123"}},
 {$unwind: "$message"}, 
 {$sort: {"message.dateCreated": 1}},
 {$group: {_id: "$_id", "message": {"$push": "$message"}}});

If you use this given query first it will filter the documents that match your criteria, then it will unwind the filtered documents.

如果您首先使用这个给定的查询,它将过滤符合您的条件的文档,然后它将展开已过滤的文档。

#2


0  

It seems like your entity classes are wrong. Why does Message have @DBRef as annotation?

似乎您的实体类是错误的。为什么消息有@DBRef作为注释?

In my opinion it should be like that:

我认为应该是这样:

@Document(collection="user")
public class User {

  @Id
  private String id;
  private String userId;
  @Field("message")
  private List<Message> message;
  //constructor, getter, setter
}

public class Message {
  private String messageId;
  private long dateCreated;
  private String body;
  private String type;
  //constructor, getter, setter
}

#1


0  

Optimize query will be:

优化查询将:

db.user.aggregate(
 {$match: {userId: "user123"}},
 {$unwind: "$message"}, 
 {$sort: {"message.dateCreated": 1}},
 {$group: {_id: "$_id", "message": {"$push": "$message"}}});

If you use this given query first it will filter the documents that match your criteria, then it will unwind the filtered documents.

如果您首先使用这个给定的查询,它将过滤符合您的条件的文档,然后它将展开已过滤的文档。

#2


0  

It seems like your entity classes are wrong. Why does Message have @DBRef as annotation?

似乎您的实体类是错误的。为什么消息有@DBRef作为注释?

In my opinion it should be like that:

我认为应该是这样:

@Document(collection="user")
public class User {

  @Id
  private String id;
  private String userId;
  @Field("message")
  private List<Message> message;
  //constructor, getter, setter
}

public class Message {
  private String messageId;
  private long dateCreated;
  private String body;
  private String type;
  //constructor, getter, setter
}