SpringData - Mongo - 聚合

时间:2015-11-13 00:05:51

标签: mongodb spring-data aggregation-framework spring-data-mongodb

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

我有以下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. 检索第一个AND和最后一个条目的创建日期
  5. 汇总所有价格并存储在&#34; totalPrice&#34;
  6. 统计所有购买并将其存储在&#34; totalCount&#34;
  7. 我尝试从这种方法开始,但我找不到如何在一个聚合管道中做所有事情的方法:

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

1 个答案:

答案 0 :(得分:3)

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

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 Data 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();