使用 Spring 数据在 Mongo 数据库中展开和拆分多个子文档

unwind and split multiple sub document in Mongo DB using Spring Data

这是存储数据的示例

[
   {
      "userId":"user123",
      "name":"John",
      "card":{
         "amount":1000.0,
         "sentMoneyList":[
            {
               "creationDate":"2019-08-07T00:00:00.000+0000",
               "shopId":"merchant1",
               "loyaltyPoint":200,
               "amount":250
            },
            {
               "creationDate":"2019-01-07T00:00:00.000+0000",
               "shopId":"merchant2",
               "loyaltyPoint":100,
               "amount":99
            }
         ],
         "receivedMoneyList":[
            {
               "creationDate":"2019-09-07T00:00:00.000+0000",
               "amount":40
            },
            {
               "creationDate":"2019-03-07T00:00:00.000+0000",
               "amount":500
            }
         ]
      }
   }
]

我想建立一个从给定日期开始的所有用户的收款和汇款时间表。 如果 startDate 是 "2019-02-01T00:00:00.000+0000",我请求的输出应该是这样的:

[
   {
      "userId":"user123",
      "name":"John",
      "card":{
         "amount":1000.0,
         "sentMoneyList":[
            {
               "creationDate":"2019-08-07T00:00:00.000+0000",
               "shopId":"merchant1",
               "loyaltyPoint":200,
               "amount":250
            }
         ]
      }
   },
   {
      "userId":"user123",
      "name":"John",
      "card":{
         "amount":1000.0,
         "receivedMoneyList":[
            {
               "creationDate":"2019-09-07T00:00:00.000+0000",
               "amount":40
            }
         ]
      }
   },
   {
      "userId":"user123",
      "name":"John",
      "card":{
         "amount":1000.0,
         "receivedMoneyList":[
            {
               "creationDate":"2019-03-07T00:00:00.000+0000",
               "amount":500
            }
         ]
      }
   }
]

此处是试图获得此结果的 java 代码:

  Criteria criteriaClient = new Criteria();  
  MatchOperation matchOperation = match(criteriaClient.orOperator(
          Criteria.where("card.sentMoneyList.creationDate").gte(startDate),
          Criteria.where("card.receivedMoneyList.creationDate").gte(startDate)));

  UnwindOperation unwindSent = Aggregation.unwind("card.sentMoneyList");
  UnwindOperation unwindReceived = Aggregation.unwind("card.receivedMoneyList");

  Aggregation aggregation = Aggregation.newAggregation(unwindSent, unwindReceived, matchOperation);

   List<UserDTO> result = mongoTemplate.aggregate(
                aggregation, "users", UserDTO.class).getMappedResults();

它给出了一个空列表。为了获得上述结果,查询中缺少什么? 谢谢

您可以使用 $facet 实现预期输出,这有助于您对传入数据进行分类。在这里,我在 sentMoney 数组中获得 sentMoneyList 数组,在 receivedMoney[ 中获得 receivedMoneyList 数组=30=]。然后聚合任何给你输出的东西。

public List<Object> test() {
    Aggregation aggregation = Aggregation.newAggregation(
        facet(
                p -> new Document("$project",
                        new Document("card.receivedMoneyList", 0)
                ),
                a -> new Document("$addFields",
                        new Document("card.sentMoneyList",
                                new Document("$filter",
                                        new Document("input", "$card.sentMoneyList")
                                                .append("cond",
                                                        new Document("$gte", Arrays.asList("$$this.creationDate", "2019-02-01T00:00:00.000+0000"))
                                                )
                                )
                        )
                ),
                unwind("$card.sentMoneyList")

        ).as("sentMoney").and(
                p -> new Document("$project",
                        new Document("card.sentMoneyList", 0)
                ),
                a -> new Document("$addFields",
                        new Document("card.receivedMoney",
                                new Document("$filter",
                                        new Document("input", "$card.receivedMoney")
                                                .append("cond",
                                                        new Document("$gte", Arrays.asList("$$this.creationDate", "2019-02-01T00:00:00.000+0000"))
                                                )
                                )
                        )
                ),
                unwind("$card.receivedMoney")
        ).as("receivedMoney"),
        p -> new Document("$project",
                new Document("combined",
                        new Document("$concatArrays", Arrays.asList("$sentMoney", "$receivedMoney"))
                )
        ),
        unwind("$combined"),
        replaceRoot("combined")

    ).withOptions(AggregationOptions.builder().allowDiskUse(Boolean.TRUE).build());

    return mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Users.class), Object.class).getMappedResults();

}

首先,我要求您使用 Object.class 来获取聚合结果,并使用 return 作为 List<Object>。如果一切正常,那么您可以将此模型转换为 UserDTO.class,其结构应与输出相同。

您添加了一个目标集合 users,这不是一个好的做法。所以使用 mongoTemplate.getCollectionName(YOUR_TARGET_COLLECTION.class)

不是:我没有尝试过这段代码,但这是基于工作 Mongo playground

编写的