簡體   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