[英]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
}
}
]);
實際結果 :
當我對這兩個組運行上面提到的完全相同的代碼時,它給了我這樣的錯誤:
但是,如果我一次使用一組運行相同的代碼,它就可以正常工作:
通過從代碼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} }] }
通過從代碼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.