Java / Mongotemplate聚合,组和总和不按预期进行分组

发布于 2025-02-08 13:28:35 字数 4488 浏览 2 评论 0原文

我有一个Mongo系列,其中包含许多文档,其中包含有关给我们用户的信用 /礼物的信息。

我希望能够运行一个汇总的查询,以获取在最后X天内收到信用 /礼物的所有用户,并将每个用户的信用额度总值汇总。

我认为我有正确的汇总,组和总代码,但是每个用户都会恢复多个对象,因为我要分组,然后将值(?)总结

为我的文档是什么结构看起来像:

    _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"),

这是我的查询代码:

    @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");
        }
    }

这也是我的映射类:

@Getter
@Setter
public class RecentlyRewardedUsers {

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

就像我上面说的那样,当查询结果映射到最近的whardrewardedusers类时,我看到了同一用户ID的多个条目(请参见下图) 。我本以为应该将其全部卷起/汇总到该用户

“在此处输入图像说明”

如果有人可以阐明我做错了什么,那真是太好了!

谢谢

**编辑** 根据以下答案 用户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);

当我现在执行上述错误时,我会收到此错误:

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

如果目前我删除了排序选项。代码将执行。但是,我没有将用户ID映射到我最近的读课上。

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

任何帮助都会很棒。

谢谢

编辑 添加图像以显示我的意思是用UserID未被映射在MappedResponse中。但是,在查询的原始响应中,用户ID被映射到documentID _id

//i.sstatic.net/qmgwn.png“ alt =”在此处输入图像描述”>

I have a mongo collection which has many documents containing information about credits / gifts given to our users.

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.

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). I would have thought it should be all rolled up / summed up into one entry for that userId

enter image description here

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:

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.

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. However in the Raw response of the query the userId is getting mapped to the documentId _id

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不打扰别人 2025-02-15 13:28:35

组中删除_id group(“ userId”,“ _id”)

这与您相似,其实现也很明确。

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源

Remove _id from 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文