简体   繁体   English

Java / MongoTemplate 聚合、组和总和未按预期分组

[英]Java / MongoTemplate Aggregation, Group and Sum not grouping as expected

I have a mongo collection which has many documents containing information about credits / gifts given to our users.我有一个 mongo 集合,其中包含许多文档,其中包含有关给予我们用户的积分/礼物的信息。

I would like to be able to run an Aggregated Query to get all the users who have received a credit / gift within the last x number of days and sum the total value of those credits for each user.我希望能够运行聚合查询以获取在过去 x 天内收到积分/礼物的所有用户,并将每个用户的积分总价值相加。

I think I have the correct Aggregation, group and sum code but I'm getting back more than one object per user, which shouldn't be the case since I'm grouping and then summing the values(?)我认为我有正确的聚合、分组和求和代码,但我得到的每个用户不止一个对象,这不应该是这种情况,因为我正在分组然后对值求和(?)

Here is what my document structure looks like:这是我的文档结构的样子:

    _id: ObjectId("61c36a8a21047124c4181271"),
    transactionId: UUID("6fbf536e-7a53-442c-9615-53e32362608b"),
    userId: 'xxxxx',
    transactionMessage: 'Account credited with: 1',
    transactionType: 'CREDIT',
    transactionAction: 'GIFT',
    inComingPaymentFromUserId: 'xxxx',
    transactionAmount: Decimal128("1"),
    customMessage: "blah'",
    createdDate: ISODate("2021-12-22T18:12:26.812Z"),
    lastUpdatedAt: ISODate("2021-12-22T18:12:26.812Z"),

And here is my query code:这是我的查询代码:

    @Override
    public List<RecentlyRewardedUsers> findRecentlyRewardedUsers(Integer range, Pageable pageable) {
        Aggregation agg = Aggregation.newAggregation(
                match(Criteria.where("createdDate").gt(LocalDate.now().minusDays(range))
                        .andOperator(Criteria.where("transactionAction").is("GIFT"))), sort(Sort.Direction.DESC, "createdDate"),
                group("userId", "_id").sum("transactionAmount").as("totalValueAwarded"),
                project("userId", "totalValueAwarded"),
                skip((long) pageable.getPageNumber() * pageable.getPageSize()),
                limit(pageable.getPageSize()));
        try {
            return mongoTemplate.aggregate(agg, "Transactions", RecentlyRewardedUsers.class).getMappedResults();
        } catch (Exception ex) {
            throw new ServiceUnavailableException("Unable to perform Mongo Operation {" + ex.getLocalizedMessage() + "}", "User");
        }
    }

Here is also my mapped class:这也是我的映射类:

@Getter
@Setter
public class RecentlyRewardedUsers {

    @Field("userId")
    private String userId;
    private String totalValueAwarded;
    private String userDisplayName;
    private String profilePicUrl;
}

Like I said above, when the the results of the query are mapped to the RecentlyRewardedUsers class, I see multiple entries for the same userId (see image below).就像我上面所说的,当查询的结果映射到 RecentRewardedUsers 类时,我看到同一个 userId 的多个条目(见下图)。 I would have thought it should be all rolled up / summed up into one entry for that userId我原以为应该将其全部汇总/汇总到该 userId 的一个条目中

在此处输入图像描述

If anyone can shed some light on what I've done wrong that would be great!!如果有人可以阐明我做错了什么,那就太好了!

Thank you谢谢

** EDIT ** Based on the answer below from user Eskandar Abedini, I've updated my code to be the following: ** 编辑 ** 根据用户 Eskandar Abedini 的以下回答,我已将代码更新为以下内容:

Criteria operator = new Criteria();
operator.andOperator(
        Criteria.where("createdDate").gt(LocalDate.now().minusDays(2))
                .andOperator(Criteria.where("transactionAction").is("GIFT")));

MatchOperation matchOperation = Aggregation.match(operator);


GroupOperation groupOperation = Aggregation.group("userId").sum("transactionAmount").as("totalValueAwarded");
List<String> sortOptions = new ArrayList<>();
sortOptions.add("createdDate");
Sort sort = new Sort(Sort.Direction.DESC, sortOptions);
SortOperation sortOperation = Aggregation.sort(sort);

Aggregation aggregation = Aggregation.newAggregation(Transaction.class, matchOperation, groupOperation, sortOperation);

AggregationResults<RecentlyRewardedUsers> aggregationResults = mongoTemplate.aggregate(aggregation, Transaction.class, RecentlyRewardedUsers.class);

When I now execute the above I get this error:当我现在执行上述操作时,我收到此错误:

java.lang.IllegalArgumentException: Invalid reference 'createdDate'!

If for the moment I remove the sort options.如果暂时我删除排序选项。 The code will execute.代码将执行。 However I'm not getting the userId mapped into my RecentlyRewarded class.但是,我没有将 userId 映射到我的 RecentRewarded 类中。

Criteria operator = new Criteria();
operator.andOperator(
        Criteria.where("createdDate").gt(LocalDate.now().minusDays(2))
                .andOperator(Criteria.where("transactionAction").is("GIFT")));

MatchOperation matchOperation = Aggregation.match(operator);


GroupOperation groupOperation = Aggregation.group("userId").sum("transactionAmount").as("totalValueAwarded");
Aggregation aggregation = Aggregation.newAggregation(Transaction.class, matchOperation, groupOperation);

AggregationResults<RecentlyRewardedUsers> aggregationResults = mongoTemplate.aggregate(aggregation, Transaction.class, RecentlyRewardedUsers.class);

Any help would be amazing.任何帮助都会很棒。

Thank you谢谢

Edit Adding image to show what I mean by userId not being mapped in the MappedResponse.编辑添加图像以显示未在 MappedResponse 中映射的 userId 的意思。 However in the Raw response of the query the userId is getting mapped to the documentId _id然而,在查询的原始响应中,userId 被映射到 documentId _id

在此处输入图像描述

Remove _id from group("userId", "_id")从组中删除_id group("userId", "_id")

This is somehow similar to yours, its implementation is clear too.这有点类似于你的,它的实现也很清楚。

public BaseResponse getErrorLogGroupByAppName() throws BaseException {

    Criteria operator = new Criteria();
    operator.andOperator(
            Criteria.where("execDate").is(DateUtil.today())
    );

    MatchOperation matchOperation = Aggregation.match(operator);


    GroupOperation groupOperation = Aggregation.group("serUrl", "serPort", "appName", "appSer", "reqUrl", "execDate").count().as("count");

    Sort sort = new Sort(new Sort.Order(Sort.Direction.DESC, "count"));
    SortOperation sortOperation = Aggregation.sort(sort);

    Aggregation aggregation = Aggregation.newAggregation(ErrorInfo.class, matchOperation, groupOperation, sortOperation);

    AggregationResults<Map> aggregationResults = template.aggregate(aggregation, ErrorInfo.class, Map.class);

    return new BaseResponse(aggregationResults.getMappedResults());
}

GitHub Source GitHub 源

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM