简体   繁体   English

带有特定条件计数的 Mongo DB 聚合并按输出投影的日期范围过滤无法按预期工作

[英]Mongo DB Aggregation with Count for Specific Conditions and filter by Date Range which Outputs a Projection Doesn't work as Expected

Please consider that I'm a beginner to MongoDB and I need to retrieve data from MongoDB database in somewhat complex query format.请考虑到我是 MongoDB 的初学者,我需要以某种复杂的查询格式从 MongoDB 数据库中检索数据。 I've referred several Questions and Answers published in the community but my expected query was much complex due to some complex counts operations for certain conditions etc. However I was able manage to retrieve the data to a very similar query result which I'm expecting.我已经参考了社区中发布的几个问题和答案,但由于某些条件下的一些复杂计数操作等,我预期的查询非常复杂。但是我能够设法将数据检索到我期望的非常相似的查询结果. But still I was unable to get the expected query result with my own.但是我仍然无法用自己的方式获得预期的查询结果。 If anyone who can help to find a solution on this matter is much appreciable.如果有人可以帮助找到有关此问题的解决方案,那将是非常值得赞赏的。

ProjectionOperation projection = project("createdAt", "status")
            .and(DateOperators.DateToString.dateOf("createdAt").toString("%Y-%m-%d")).as("otpDate")
            .and(ConditionalOperators.when(ComparisonOperators.Eq.valueOf("status").equalToValue("VERIFIED")).then(1).otherwise(0)).as("verifyStatus");

// Group by otpDate created in projection to get total otp count by date-wise
GroupOperation totalCount = group("otpDate").count().as("totalCount");

// Group by verifyStatus  created in projection to get total verified OTPs by status "VERIFIED"
GroupOperation loggedInCount = group( "verifyStatus").sum("verifyStatus").as("loggedIn");

// Filter data for given specific date range
MatchOperation match = match(Criteria.where("createdAt").gte(from).lte(to));

// Sort the result to ascending order by _id 
SortOperation sortOperation = sort(Sort.Direction.ASC, "_id");

final TypedAggregation<Otp> aggregation = newAggregation(
            Otp.class, match, projection, totalCount, loggedInCount, sortOperation);

mongoTemplate.aggregate(aggregation, OtpProjDto.class).getMappedResults();

Please find the Projection Dto, Expected and the Actual Results I've mentioned below with this code.请使用此代码找到我在下面提到的投影 Dto、预期和实际结果。

OtpProjDto.java OtpProjDto.java

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.io.Serializable;
import java.math.BigInteger;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class OtpProjDto implements Serializable {

    private String createdAt;
    private BigInteger totalCount;
    private BigInteger loggedIn;
}

Expected Result :预期结果 :

db.otp.aggregate([
{
    $match: {

        "createdAt": {
            $gte: new ISODate("2021-03-10"),
            $lte: new ISODate("2021-03-31")
        }
    }
},
{
    $group: {
        _id: {
            $dateToString: {
                format: "%Y-%m-%d",
                date: "$createdAt"
            }
        },
        "totalCount": {
            "$sum": 1
        },
        "logged_in": {
            "$sum": {
                "$cond": [{"$eq": ["$status", "VERIFIED"]}, 1, 0]
            }
        }
    }
},
{
    $sort: {
        _id: 1
    }
}
]);

Actual Result :实际结果 :

When I run the exact same code I've mentioned above with the two group it gives me an error like this:当我对这两个组运行上面提到的完全相同的代码时,它给了我这样的错误:

这是错误

But if I run the same code with one grouping at one time it works perfectly fine:但是,如果我一次使用一组运行相同的代码,它就可以正常工作:

  1. By commenting out this line from the code GroupOperation loggedInCount = group("verifyStatus").sum("verifyStatus").as("loggedIn");通过从代码GroupOperation loggedInCount = group("verifyStatus").sum("verifyStatus").as("loggedIn");注释掉这一行GroupOperation loggedInCount = group("verifyStatus").sum("verifyStatus").as("loggedIn"); result is:结果是:

     { "aggregate": "__collection__", "pipeline": [{ "$match": { "createdAt": { "$gte": {"$java": 2021 - 03 - 10}, "$lte": {"$java": 2021 - 03 - 31} } } }, { "$project": { "createdAt": 1, "status": 1, "otpDate": {"$dateToString": {"format": "%Y-%m-%d", "date": "$createdAt"}}, "verifyStatus": {"$cond": {"if": {"$eq": ["$status", "VERIFIED"]}, "then": 1, "else": 0}} } }, { "$group": { "_id": "$otpDate", "totalCount": {"$sum": 1} } }, { "$sort": {"_id": 1} }] }
  2. By commenting out this line from the code GroupOperation totalCount = group("otpDate").count().as("totalCount") result is:通过从代码GroupOperation totalCount = group("otpDate").count().as("totalCount")注释掉这一行,结果是:

     { "aggregate" : "__collection__", "pipeline": [{ "$match": { "createdAt": { "$gte": {"$java": 2021 - 03 - 10}, "$lte": {"$java": 2021 - 03 - 31} } } }, { "$project": { "createdAt": 1, "status": 1, "otpDate": {"$dateToString": {"format": "%Y-%m-%d", "date": "$createdAt"}}, "verifyStatus": {"$cond": {"if": {"$eq": ["$status", "VERIFIED"]}, "then": 1, "else": 0}} } }, { "$group": { "_id": "$verifyStatus", "loggedIn": {"$sum": "$verifyStatus"} } }, { "$sort": {"_id": 1} }]; }

I think the issue is with the multiple grouping.我认为问题在于多个分组。 If anyone who can help to find a solution on this matter is much appreciable.如果有人可以帮助找到有关此问题的解决方案,那将是非常值得赞赏的。

After doing some researches by referring documentations and articles and spending some time with the above code I was able to find the solution for the above problem.通过参考文档和文章进行了一些研究并花一些时间使用上述代码后,我能够找到上述问题的解决方案。

The problem was the exact thing what I suspected and it was the issue with trying to add two groups (more than one) grouping by different columns.问题正是我所怀疑的,它是尝试添加两组(多个)按不同列分组的问题。 So, I fixed this issue mainly by joining the second group count result using push() method with the first group I've used.因此,我主要通过使用push()方法将第二组计数结果与我使用的第一组连接来解决此问题。 So, this fixed my issue.所以,这解决了我的问题。

ProjectionOperation projection = project("createdAt", "status")
            .and(DateOperators.DateToString.dateOf("createdAt").toString("%Y-%m-%d")).as("otpDate")
            .and(AccumulatorOperators.Sum.sumOf(ConditionalOperators.when(ComparisonOperators.Eq.valueOf("status")
                    .equalToValue("VERIFIED")).then(1).otherwise(0))).as("verifyStatus"); // <--- (1) This Line Changed

// Joined the two group result into one result
GroupOperation totalCount = group("otpDate").count().as("totalCount")
            .push("verifyStatus").as("loggedIn"); // <--- (2) This Line Changed

// Filter-data for given specific-dates-range
MatchOperation match = match(Criteria.where("createdAt").gte(from).lte(to));

// Sort the result to ascending order by _id
SortOperation sortOperation = sort(Sort.Direction.ASC, "_id");

final TypedAggregation<Otp> aggregation = newAggregation(
            Otp.class, match, projection, totalCount, sortOperation);

mongoTemplate.aggregate(aggregation, OtpGenerationDataDto.class).getMappedResults()

Current Actual Result :当前实际结果:

在此处输入图片说明

    {
    "aggregate": "__collection__",
    "pipeline": [{
        "$match": {
            "createdAt": {
                "$gte": {"$java": 2021 - 03 - 10},
                "$lte": {"$java": 2021 - 03 - 31}
            }
        }
    }, {
        "$project": {
            "createdAt": 1,
            "status": 1,
            "otpDate": {"$dateToString": {"format": "%Y-%m-%d", "date": "$createdAt"}},
            "verifyStatus": {"$sum": {"$cond": {"if": {"$eq": ["$status", "VERIFIED"]}, "then": 1, "else": 0}}}
        }
    }, {
        "$group": {
            "_id": "$otpDate",
            "totalCount": {"$sum": 1},
            "loggedIn": {"$push": "$verifyStatus"}
        }
    }, {
        "$sort": {"_id": 1}
    }];
}

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

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