일별 그룹 내 MongoDB 집계
mongo에 다음과 같은 문서가 있습니다.
{
_id : ObjectId("..."),
"make" : "Nissan",
..
},
{
_id : ObjectId("..."),
"make" : "Nissan",
"saleDate" : ISODate("2013-04-10T12:39:50.676Z"),
..
}
이상적으로는 하루에 판매되는 차량의 수를 제조사별로 세어보고 싶습니다.그런 다음 오늘 또는 오늘과 같은 창을 지난 7일까지 보고 싶습니다.
나는 몇몇 추악한 코드로 일일 뷰를 달성할 수 있었습니다.
db.inventory.aggregate(
{ $match : { "saleDate" : { $gte: ISODate("2013-04-10T00:00:00.000Z"), $lt: ISODate("2013-04-11T00:00:00.000Z") } } } ,
{ $group : { _id : { make : "$make", saleDayOfMonth : { $dayOfMonth : "$saleDate" } }, cnt : { $sum : 1 } } }
)
그러면 결과가 나옵니다.
{
"result" : [
{
"_id" : {
"make" : "Nissan",
"saleDayOfMonth" : 10
},
"cnt" : 2
},
{
"_id" : {
"make" : "Toyota",
"saleDayOfMonth" : 10
},
"cnt" : 4
},
],
"ok" : 1
}
따라서 괜찮지만 쿼리에서 두 날짜 값을 변경하지 않는 것이 좋습니다.그런 다음 위에서 언급한 대로 (매번 수정하지 않고) 이 쿼리를 실행하여 지난 한 주 동안 동일한 결과를 매일 확인할 수 있었으면 합니다.
아, 그리고 여기 제가 쿼리에 사용한 샘플 데이터가 있습니다.
db.inventory.save({"make" : "Nissan","saleDate" : ISODate("2013-04-10T12:39:50.676Z")});
db.inventory.save({"make" : "Nissan"});
db.inventory.save({"make" : "Nissan","saleDate" : ISODate("2013-04-10T11:39:50.676Z")});
db.inventory.save({"make" : "Toyota","saleDate" : ISODate("2013-04-09T11:39:50.676Z")});
db.inventory.save({"make" : "Toyota","saleDate" : ISODate("2013-04-10T11:38:50.676Z")});
db.inventory.save({"make" : "Toyota","saleDate" : ISODate("2013-04-10T11:37:50.676Z")});
db.inventory.save({"make" : "Toyota","saleDate" : ISODate("2013-04-10T11:36:50.676Z")});
db.inventory.save({"make" : "Toyota","saleDate" : ISODate("2013-04-10T11:35:50.676Z")});
잘 부탁드립니다, 케빈.
Mongo 2.8 RC2에는 $dateToString이라는 새로운 데이터 집계 연산자가 있습니다. $dateToString은 하루 단위로 그룹화하고 결과적으로 "YYY-MM-DD"를 가질 수 있습니다.
설명서의 예:
db.sales.aggregate(
[
{
$project: {
yearMonthDay: { $dateToString: { format: "%Y-%m-%d", date: "$date" } },
time: { $dateToString: { format: "%H:%M:%S:%L", date: "$date" } }
}
}
]
)
결과:
{ "_id" : 1, "yearMonthDay" : "2014-01-01", "time" : "08:15:39:736" }
업데이트 업데이트된 답변은 3.6의 날짜 기능을 기반으로 하며 매출이 없는 범위의 날짜를 포함하는 방법을 보여줍니다(내 원래 답변에는 언급되지 않았습니다).
표본 데이터:
db.inventory.find()
{ "_id" : ObjectId("5aca30eefa1585de22d7095f"), "make" : "Nissan", "saleDate" : ISODate("2013-04-10T12:39:50.676Z") }
{ "_id" : ObjectId("5aca30eefa1585de22d70960"), "make" : "Nissan" }
{ "_id" : ObjectId("5aca30effa1585de22d70961"), "make" : "Nissan", "saleDate" : ISODate("2013-04-10T11:39:50.676Z") }
{ "_id" : ObjectId("5aca30effa1585de22d70962"), "make" : "Toyota", "saleDate" : ISODate("2013-04-09T11:39:50.676Z") }
{ "_id" : ObjectId("5aca30effa1585de22d70963"), "make" : "Toyota", "saleDate" : ISODate("2013-04-10T11:38:50.676Z") }
{ "_id" : ObjectId("5aca30effa1585de22d70964"), "make" : "Toyota", "saleDate" : ISODate("2013-04-10T11:37:50.676Z") }
{ "_id" : ObjectId("5aca30effa1585de22d70965"), "make" : "Toyota", "saleDate" : ISODate("2013-04-10T11:36:50.676Z") }
{ "_id" : ObjectId("5aca30effa1585de22d70966"), "make" : "Toyota", "saleDate" : ISODate("2013-04-10T11:35:50.676Z") }
{ "_id" : ObjectId("5aca30f9fa1585de22d70967"), "make" : "Toyota", "saleDate" : ISODate("2013-04-11T11:35:50.676Z") }
{ "_id" : ObjectId("5aca30fffa1585de22d70968"), "make" : "Toyota", "saleDate" : ISODate("2013-04-13T11:35:50.676Z") }
{ "_id" : ObjectId("5aca3921fa1585de22d70969"), "make" : "Honda", "saleDate" : ISODate("2013-04-13T00:00:00Z") }
정의startDate
그리고.endDate
변수로 사용하고 집계에 사용합니다.
startDate = ISODate("2013-04-08T00:00:00Z");
endDate = ISODate("2013-04-15T00:00:00Z");
db.inventory.aggregate([
{ $match : { "saleDate" : { $gte: startDate, $lt: endDate} } },
{$addFields:{
saleDate:{$dateFromParts:{
year:{$year:"$saleDate"},
month:{$month:"$saleDate"},
day:{$dayOfMonth:"$saleDate"}
}},
dateRange:{$map:{
input:{$range:[0, {$subtract:[endDate,startDate]}, 1000*60*60*24]},
in:{$add:[startDate, "$$this"]}
}}
}},
{$unwind:"$dateRange"},
{$group:{
_id:"$dateRange",
sales:{$push:{$cond:[
{$eq:["$dateRange","$saleDate"]},
{make:"$make",count:1},
{count:0}
]}}
}},
{$sort:{_id:1}},
{$project:{
_id:0,
saleDate:"$_id",
totalSold:{$sum:"$sales.count"},
byBrand:{$arrayToObject:{$reduce:{
input: {$filter:{input:"$sales",cond:"$$this.count"}},
initialValue: {$map:{input:{$setUnion:["$sales.make"]}, in:{k:"$$this",v:0}}},
in:{$let:{
vars:{t:"$$this",v:"$$value"},
in:{$map:{
input:"$$v",
in:{
k:"$$this.k",
v:{$cond:[
{$eq:["$$this.k","$$t.make"]},
{$add:["$$this.v","$$t.count"]},
"$$this.v"
]}
}
}}
}}
}}}
}}
])
샘플 데이터에 대해 다음과 같은 결과를 제공합니다.
{ "saleDate" : ISODate("2013-04-08T00:00:00Z"), "totalSold" : 0, "byBrand" : { } }
{ "saleDate" : ISODate("2013-04-09T00:00:00Z"), "totalSold" : 1, "byBrand" : { "Toyota" : 1 } }
{ "saleDate" : ISODate("2013-04-10T00:00:00Z"), "totalSold" : 6, "byBrand" : { "Nissan" : 2, "Toyota" : 4 } }
{ "saleDate" : ISODate("2013-04-11T00:00:00Z"), "totalSold" : 1, "byBrand" : { "Toyota" : 1 } }
{ "saleDate" : ISODate("2013-04-12T00:00:00Z"), "totalSold" : 0, "byBrand" : { } }
{ "saleDate" : ISODate("2013-04-13T00:00:00Z"), "totalSold" : 2, "byBrand" : { "Honda" : 1, "Toyota" : 1 } }
{ "saleDate" : ISODate("2013-04-14T00:00:00Z"), "totalSold" : 0, "byBrand" : { } }
이 집계는 또한 두 가지를 사용하여 수행할 수 있습니다.$group
무대와 간단한 것들$project
대신에$group
그리고 콤플렉스$project
여기 있습니다.
db.inventory.aggregate([
{$match : { "saleDate" : { $gte: startDate, $lt: endDate} } },
{$addFields:{saleDate:{$dateFromParts:{year:{$year:"$saleDate"}, month:{$month:"$saleDate"}, day:{$dayOfMonth : "$saleDate" }}},dateRange:{$map:{input:{$range:[0, {$subtract:[endDate,startDate]}, 1000*60*60*24]},in:{$add:[startDate, "$$this"]}}}}},
{$unwind:"$dateRange"},
{$group:{
_id:{date:"$dateRange",make:"$make"},
count:{$sum:{$cond:[{$eq:["$dateRange","$saleDate"]},1,0]}}
}},
{$group:{
_id:"$_id.date",
total:{$sum:"$count"},
byBrand:{$push:{k:"$_id.make",v:{$sum:"$count"}}}
}},
{$sort:{_id:1}},
{$project:{
_id:0,
saleDate:"$_id",
totalSold:"$total",
byBrand:{$arrayToObject:{$filter:{input:"$byBrand",cond:"$$this.v"}}}
}}
])
동일한 결과:
{ "saleDate" : ISODate("2013-04-08T00:00:00Z"), "totalSold" : 0, "byBrand" : { "Honda" : 0, "Toyota" : 0, "Nissan" : 0 } }
{ "saleDate" : ISODate("2013-04-09T00:00:00Z"), "totalSold" : 1, "byBrand" : { "Honda" : 0, "Nissan" : 0, "Toyota" : 1 } }
{ "saleDate" : ISODate("2013-04-10T00:00:00Z"), "totalSold" : 6, "byBrand" : { "Honda" : 0, "Toyota" : 4, "Nissan" : 2 } }
{ "saleDate" : ISODate("2013-04-11T00:00:00Z"), "totalSold" : 1, "byBrand" : { "Toyota" : 1, "Honda" : 0, "Nissan" : 0 } }
{ "saleDate" : ISODate("2013-04-12T00:00:00Z"), "totalSold" : 0, "byBrand" : { "Toyota" : 0, "Nissan" : 0, "Honda" : 0 } }
{ "saleDate" : ISODate("2013-04-13T00:00:00Z"), "totalSold" : 2, "byBrand" : { "Honda" : 1, "Toyota" : 1, "Nissan" : 0 } }
{ "saleDate" : ISODate("2013-04-14T00:00:00Z"), "totalSold" : 0, "byBrand" : { "Toyota" : 0, "Honda" : 0, "Nissan" : 0 } }
2.6에 기반한 원답:
여기에서 Aggregation Framework의 다양한 날짜 조작을 처리하는 방법에 대한 블로그 항목을 살펴보실 수 있습니다.
사용할 수 있는 것은$project
단계를 수행하여 날짜를 일일 해상도로 잘라낸 다음 전체 데이터 세트(또는 데이터 세트의 일부만)에 대해 집계를 실행하고 날짜별로 집계합니다.
샘플 데이터를 사용하여 올해 제조업체별, 날짜별로 판매한 차량 수를 알고 싶다고 가정해 보십시오.
match={"$match" : {
"saleDate" : { "$gt" : new Date(2013,0,1) }
}
};
proj1={"$project" : {
"_id" : 0,
"saleDate" : 1,
"make" : 1,
"h" : {
"$hour" : "$saleDate"
},
"m" : {
"$minute" : "$saleDate"
},
"s" : {
"$second" : "$saleDate"
},
"ml" : {
"$millisecond" : "$saleDate"
}
}
};
proj2={"$project" : {
"_id" : 0,
"make" : 1,
"saleDate" : {
"$subtract" : [
"$saleDate",
{
"$add" : [
"$ml",
{
"$multiply" : [
"$s",
1000
]
},
{
"$multiply" : [
"$m",
60,
1000
]
},
{
"$multiply" : [
"$h",
60,
60,
1000
]
}
]
}
]
}
}
};
group={"$group" : {
"_id" : {
"m" : "$make",
"d" : "$saleDate"
},
"count" : {
"$sum" : 1
}
}
};
이제 집계를 실행하면 다음과 같은 이점을 얻을 수 있습니다.
db.inventory.aggregate(match, proj1, proj2, group)
{
"result" : [
{
"_id" : {
"m" : "Toyota",
"d" : ISODate("2013-04-10T00:00:00Z")
},
"count" : 4
},
{
"_id" : {
"m" : "Toyota",
"d" : ISODate("2013-04-09T00:00:00Z")
},
"count" : 1
},
{
"_id" : {
"m" : "Nissan",
"d" : ISODate("2013-04-10T00:00:00Z")
},
"count" : 2
}
],
"ok" : 1
}
출력을 설정하기 위해 다른 {$project} 단계를 추가하고 {$sort} 단계를 추가할 수 있지만 기본적으로 각 날짜에 대해 판매 수량을 계산할 수 있습니다.
사용자 1083621의 답변이 마음에 들지만 이 방법은 다음 집계 파이프라인 단계에서 날짜 필드로 사용할 수 없기 때문에 이 필드를 따르는 작업에 몇 가지 제한을 줍니다.날짜 집계 작업을 비교하거나 사용할 수 없으며 집계 후 문자열(!)이 표시됩니다.이 모든 것은 원래 날짜 필드를 투영하여 해결할 수 있지만, 이 경우 그룹화 단계를 통해 유지하는 데 어려움을 겪을 수 있습니다.그리고 결국, 때때로 여러분은 임의적인 낮 시간이 아니라 하루의 시작으로 조작하기를 원합니다.제 방법은 다음과 같습니다.
{'$project': {
'start_of_day': {'$subtract': [
'$date',
{'$add': [
{'$multiply': [{'$hour': '$date'}, 3600000]},
{'$multiply': [{'$minute': '$date'}, 60000]},
{'$multiply': [{'$second': '$date'}, 1000]},
{'$millisecond': '$date'}
]}
]},
}}
다음과 같은 이점이 있습니다.
{
"start_of_day" : ISODate("2015-12-03T00:00:00.000Z")
},
{
"start_of_day" : ISODate("2015-12-04T00:00:00.000Z")
}
사용자 1083621의 방법보다 더 빠른지 알 수 없습니다.
언급URL : https://stackoverflow.com/questions/15938859/mongodb-aggregate-within-daily-grouping
'programing' 카테고리의 다른 글
SVN을 사용해야 합니까 아니면 Git을 사용해야 합니까? (0) | 2023.05.21 |
---|---|
Excel의 VBA 기능이 범위를 반환할 수 있습니까? (0) | 2023.05.21 |
Cocoapod를 사용한 Xcode 장치 테스트 (0) | 2023.05.21 |
VB - C# 함수 (0) | 2023.05.21 |
Angular 2에서 EventEmitter.next()와 EventEmitter.emit()의 차이 (0) | 2023.05.21 |