繁体   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

请考虑到我是 MongoDB 的初学者,我需要以某种复杂的查询格式从 MongoDB 数据库中检索数据。 我已经参考了社区中发布的几个问题和答案,但由于某些条件下的一些复杂计数操作等,我预期的查询非常复杂。但是我能够设法将数据检索到我期望的非常相似的查询结果. 但是我仍然无法用自己的方式获得预期的查询结果。 如果有人可以帮助找到有关此问题的解决方案,那将是非常值得赞赏的。

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

请使用此代码找到我在下面提到的投影 Dto、预期和实际结果。

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

预期结果 :

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

实际结果 :

当我对这两个组运行上面提到的完全相同的代码时,它给了我这样的错误:

这是错误

但是,如果我一次使用一组运行相同的代码,它就可以正常工作:

  1. 通过从代码GroupOperation loggedInCount = group("verifyStatus").sum("verifyStatus").as("loggedIn");注释掉这一行GroupOperation loggedInCount = group("verifyStatus").sum("verifyStatus").as("loggedIn"); 结果是:

     { "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. 通过从代码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} }]; }

我认为问题在于多个分组。 如果有人可以帮助找到有关此问题的解决方案,那将是非常值得赞赏的。

通过参考文档和文章进行了一些研究并花一些时间使用上述代码后,我能够找到上述问题的解决方案。

问题正是我所怀疑的,它是尝试添加两组(多个)按不同列分组的问题。 因此,我主要通过使用push()方法将第二组计数结果与我使用的第一组连接来解决此问题。 所以,这解决了我的问题。

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

当前实际结果:

在此处输入图片说明

    {
    "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