Spring Data – Mongo – 聚合

SpringData – Mongo – Aggregation

我与 MongoDB 和 Spring 数据的聚合框架斗争了很长一段时间,我实际上想知道我想做的事情是否真的可行。

我有以下 Mongo 个文件:

{
  "_id": ObjectId("564520fad4c64dd36fb1f0a4"),
  "_class": "com.sample.Purchase",
  "created": new Date(1447371002645),
  "productId": NumberLong(12),
  "clientId": "c1",
  "price": NumberLong(20)
}

我想创建以下统计数据:

List<ClientStatsEntry> entries;

public class ClientStatsEntry  {
   private String clientId;
   private Date firstSeen;
   private Date lastSeen;
   private Long totalPriceSpend;
   private long totalCount;
}

所以基本上步骤是:

  1. 按 productId 过滤集合(匹配)
  2. 按 clientIds (groupBy) 拆分所有剩余元素
  3. 检索第一个和最后一个条目的创建日期
  4. 汇总所有价格并存储在"totalPrice"
  5. 计算所有购买并将其存储在"totalCount"

我试图从这种方法开始,但我找不到一种方法可以在一个聚合管道中完成所有事情:

Aggregation agg = newAggregation(
            match(Criteria.where("productId").is(productId)),
            group("clientId").sum("price").as("totalPriceSpend"),
            Aggregation.project("totalPriceSpend", "productId").and("productId").previousOperation());

我相信您正在寻找这个聚合管道(注释表示概述的步骤):

db.purchase.aggregate([
    /* 1. Filter collection by productId (match) */
    {
        "$match": {
            "productId": productId
        }
    },
    /* 2. Split all remaining elements by clientIds (groupBy) */
    {
        "$group": {
            "_id": "$clientId",
            "firstSeen": { "$min": "$createdDate"}, // 3. a) Retrieve the created date of the first entry
            "lastSeen": { "$max": "$createdDate"}, // 3. b) Retrieve the created date of the last entry
            /* 4. Sum up all prices and store in "totalPrice" */
            "totalPriceSpend": {
                "$sum": "$price"
            },
            /* 5. Count all purchases and store it in "totalCount" */
            "totalCount": {
                "$sum": 1
            }
        }
    }
])

Spring 数据 MongoDB 聚合等效如下:

Aggregation agg = Aggregation.newAggregation( 
    match(Criteria.where("productId").is(productId)),
    group("clientId")
        .min("createdDate").as("firstSeen")
        .max("createdDate").as("lastSeen")
        .sum("price").as("totalPriceSpend")
        .count().as("totalCount"),
    project("firstSeen", "lastSeen", "totalPriceSpend", "totalCount")
        .and("clientId").previousOperation()
); 
AggregationResults<ClientStatsEntry> result = 
    mongoTemplate.aggregate(agg, ClientStatsEntry.class);
List<ClientStatsEntry> clientStatsList = result.getMappedResults();