mongodb로 날짜별로 분류하다
토픽의 클릭수를 추적하는 프로젝트를 진행하고 있습니다.
mongodb를 사용하고 있는데 클릭수를 날짜별로 그룹화해야 합니다(데이터를 15일간 그룹화 하고 싶습니다).
mongodb에 다음과 같은 형식의 데이터 저장소를 가지고 있습니다.
{
"_id" : ObjectId("4d663451d1e7242c4b68e000"),
"date" : "Mon Dec 27 2010 18:51:22 GMT+0000 (UTC)",
"topic" : "abc",
"time" : "18:51:22"
}
{
"_id" : ObjectId("4d6634514cb5cb2c4b69e000"),
"date" : "Mon Dec 27 2010 18:51:23 GMT+0000 (UTC)",
"topic" : "bce",
"time" : "18:51:23"
}
토픽의 클릭수를 일수별로 그룹화하고 싶다.나는 그것을 그룹화하는 방법을 알고 있지만, 내 데이터베이스에 저장된 날짜별로 그룹화하는 방법을 알고 있다.
다음과 같은 형식의 결과를 찾고 있습니다.
[
{
"date" : "date in log",
"click" : 9
},
{
"date" : "date in log",
"click" : 19
},
]
코드를 쓰고 있습니다만, 날짜가 문자열로 되어 있는 경우에만 동작합니다(코드는 이쪽 http://pastebin.com/2wm1n1ix) ...그룹화 방법을 가르쳐 주세요).
Mongo 어그리게이션 프레임워크를 사용한 새로운 답변
이 질문에 대한 답변이 있은 후 10gen은 집약 프레임워크와 함께 Mongodb 버전 2.2를 출시했습니다.이것은 현재 이러한 종류의 쿼리를 수행하는 더 나은 방법입니다.날짜별로 그룹화하고 저장된 값은 타임스탬프이기 때문에 이 쿼리는 조금 어렵습니다.따라서 타임스탬프를 일치하는 날짜로 변환하려면 어떤 작업을 수행해야 합니다.예를 들어 올바른 카운트를 얻을 수 있는 쿼리를 작성합니다.
db.col.aggregate(
{ $group: { _id: { $dayOfYear: "$date"},
click: { $sum: 1 } } }
)
이렇게 하면 다음과 같은 결과가 반환됩니다.
[
{
"_id" : 144,
"click" : 165
},
{
"_id" : 275,
"click" : 12
}
]
'어울리다'를 써야 요.$match
및 관심 있는 날짜 범위로 합니다.$project
을 바꾸다_id
로로 합니다.date
. 다시 년의 날짜를 날짜로 변환하는 방법은 독자에게 연습으로 남습니다. :- )
10gen에는 북마크할 가치가 있는 편리한 SQL-Mongo Aggregation 변환 차트가 있습니다.날짜 집계 연산자에 대한 특정 기사도 있습니다.
다음과 같은 기능을 이용할 수 있습니다.
db.col.aggregate([
{ $group: {
_id: {
$add: [
{ $dayOfYear: "$date"},
{ $multiply:
[400, {$year: "$date"}]
}
]},
click: { $sum: 1 },
first: {$min: "$date"}
}
},
{ $sort: {_id: -1} },
{ $limit: 15 },
{ $project: { date: "$first", click: 1, _id: 0} }
])
되고 매일 됩니다.date
★★★★★★★★★★★★★★★★:
[
{
"click" : 431,
"date" : ISODate("2013-05-11T02:33:45.526Z")
},
{
"click" : 702,
"date" : ISODate("2013-05-08T02:11:00.503Z")
},
...
{
"click" : 814,
"date" : ISODate("2013-04-25T00:41:45.046Z")
}
]
이 질문에는 이미 많은 답이 있지만, 나는 그들 중 어느 것에도 만족하지 못했다.MongoDB는 수년간 개선되어 왔으며, 이제는 이를 위한 더 쉬운 방법이 있습니다.Jonas Tomanga의 대답은 맞지만, 조금 복잡합니다.
MongoDB 3.0 이후를 사용하는 경우 날짜별로 그룹화할 수 있습니다. ★★★★★★★★★★★★로 시작합니다.$match
결과 제한 방법도 묻기 때문에 집계를 할 수 있습니다.
db.yourCollection.aggregate([
{ $match: { date: { $gte: ISODate("2019-05-01") } } },
{ $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: "$date"} }, count: { $sum: 1 } } },
{ $sort: { _id: 1} }
])
mongodb에서 날짜별로 데이터 그룹을 가져오려면 다음과 같이 하십시오.
db.getCollection('supportIssuesChat').aggregate([
{
$group : {
_id :{ $dateToString: { format: "%Y-%m-%d", date: "$createdAt"} },
list: { $push: "$$ROOT" },
count: { $sum: 1 }
}
}
])
답변이 늦었지만 (이 페이지에 접속한 다른 사용자의 경우) 기록에 대해:키는 실제로 날짜 자체가 아니라 이벤트 날짜(즉, 날짜에서 추출된 날짜)의 함수가 되므로 'key' 대신 'keyf' 인수를 사용해야 합니다.이것은, 고객이 원하는 것을 실현합니다.
db.coll.group(
{
keyf: function(doc) {
var date = new Date(doc.date);
var dateKey = (date.getMonth()+1)+"/"+date.getDate()+"/"+date.getFullYear()+'';
return {'day':dateKey};
},
cond: {topic:"abc"},
initial: {count:0},
reduce: function(obj, prev) {prev.count++;}
});
상세한 것에 대하여는, MongoDB의 어그리게이션 및 그룹에 관한 문서 페이지를 참조해 주세요.http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group
이것이 도움이 된다
return new Promise(function(resolve, reject) {
db.doc.aggregate(
[
{ $match: {} },
{ $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: "$date" } }, count: { $sum: 1 } } },
{ $sort: { _id: 1 } }
]
).then(doc => {
/* if you need a date object */
doc.forEach(function(value, index) {
doc[index]._id = new Date(value._id);
}, this);
resolve(doc);
}).catch(reject);
}
MongoDB는 MongoDB를 사용합니다.하지만 자바스크립트를 풀로 사용할 수 없습니까?
Javascript로 날짜를 해석할 수 .Date
속성에 합니다.class는 "out" 속성으로 설정합니다.키가 이미 있는 경우에는 항상 키를 추가하고, 그렇지 않은 경우에는 값 = 1(첫 번째 클릭)로 새로 생성합니다.다음은 조정된 축소 기능이 있는 코드입니다(테스트되지 않은 코드!).
db.coll.group(
{
key:{'date':true},
initial: {retVal: {}},
reduce: function(doc, prev){
var date = new Date(doc.date);
var dateKey = date.getFullYear()+''+date.getMonth()+''+date.getDate();
(typeof prev.retVal[dateKey] != 'undefined') ? prev.retVal[dateKey] += 1 : prev.retVal[dateKey] = 1;
},
cond: {topic:"abc"}
}
)
@mindthief님 감사합니다.당신의 답변이 오늘의 문제를 해결하는 데 도움이 됩니다.아래 함수는 낮별로 그룹화하기가 조금 더 쉬워지고, 희망은 다른 사람들을 도울 수 있습니다.
/**
* group by day
* @param query document {key1:123,key2:456}
*/
var count_by_day = function(query){
return db.action.group(
{
keyf: function(doc) {
var date = new Date(doc.time);
var dateKey = (date.getMonth()+1)+"/"+date.getDate()+"/"+date.getFullYear();
return {'date': dateKey};
},
cond:query,
initial: {count:0},
reduce: function(obj, prev) {
prev.count++;
}
});
}
count_by_day({this:'is',the:'query'})
또 늦은 답변이지만, 그래도.따라서 이 작업을 한 번에 수행하고 날짜 및 주제별로 그룹화된 클릭 수를 얻으려면 다음 코드를 사용할 수 있습니다.
db.coll.group(
{
$keyf : function(doc) {
return { "date" : doc.date.getDate()+"/"+doc.date.getMonth()+"/"+doc.date.getFullYear(),
"topic": doc.topic };
},
initial: {count:0},
reduce: function(obj, prev) { prev.count++; }
})
또한 제안된 대로 쿼리를 최적화하려면 String 대신 날짜(hint: use value Of())에 정수 값을 사용할 수 있습니다.단, 이 예에서는 속도가 동일합니다.
또한 MongoDB 문서는 항상 새로운 기능을 추가하므로 정기적으로 확인하는 것이 좋습니다.예를 들어 2.2 버전으로 출시되는 새로운 Aggregation 프레임워크를 사용하면 동일한 결과를 훨씬 쉽게 얻을 수 있습니다.http://docs.mongodb.org/manual/applications/aggregation/
날짜 오젝트를 직접 반환하려면
그런 다음 날짜 집계 연산자를 적용하는 대신 "날짜 산술"을 적용하여 날짜 개체를 반올림합니다.모든 드라이버가 BSON Date를 가능한 모든 언어의 Date 조작에 일반적으로 사용되는 형식으로 나타내므로 이 방법이 바람직할 수 있습니다.
db.datetest.aggregate([
{ "$group": {
"_id": {
"$add": [
{ "$subtract": [
{ "$subtract": [ "$date", new Date(0) ] },
{ "$mod": [
{ "$subtract": [ "$date", new Date(0) ] },
1000 * 60 * 60 * 24
]}
]},
new Date(0)
]
},
"click": { "$sum": 1 }
}}
])
필요한 이 15일임을 한 바와 '버킷'을 '버킷' 15일의 .$mod
:
db.datetest.aggregate([
{ "$group": {
"_id": {
"$add": [
{ "$subtract": [
{ "$subtract": [ "$date", new Date(0) ] },
{ "$mod": [
{ "$subtract": [ "$date", new Date(0) ] },
1000 * 60 * 60 * 24 * 15
]}
]},
new Date(0)
]
},
"click": { "$sum": 1 }
}}
])
적용되는 기본적인 수학은 너희 둘이Date
반환되는 객체의 값은 밀리초 단위입니다.는 에포크로 됩니다.Date(0)
어떤 언어 생성자를 사용하든 변환의 기반으로 삼을 수 있습니다.
수치에서는 modulo( )가 적용되어 날짜를 반올림합니다(나머지는 나눗셈에서 뺀 값).다음 중 하나:
1000밀리초 x 60초 x 60분 x 24시간 = 1일
또는
1000밀리초 x 60초 * 60분 * 24시간 * 15일 = 15일
따라서 원하는 간격에 유연하게 대응할 수 있습니다.
상기의 동일한 토큰에 의해 "숫자" 값과Date
오브젝트는 를 반환한다.Date
양쪽 오브젝트의 밀리초 값에 해당하는 오브젝트(epoch는 0이므로 0 더하기 차이는 변환된 날짜)
다음 목록에 쉽게 나타나 재현할 수 있습니다.
var now = new Date();
var bulk = db.datetest.initializeOrderedBulkOp();
for ( var x = 0; x < 60; x++ ) {
bulk.insert({ "date": new Date( now.valueOf() + ( 1000 * 60 * 60 * 24 * x ))});
}
bulk.execute();
그리고 15일 간격으로 두 번째 예를 실행합니다.
{ "_id" : ISODate("2016-04-14T00:00:00Z"), "click" : 12 }
{ "_id" : ISODate("2016-03-30T00:00:00Z"), "click" : 15 }
{ "_id" : ISODate("2016-03-15T00:00:00Z"), "click" : 15 }
{ "_id" : ISODate("2016-02-29T00:00:00Z"), "click" : 15 }
{ "_id" : ISODate("2016-02-14T00:00:00Z"), "click" : 3 }
또는 목록이 실행된 현재 날짜에 따라 분포가 비슷합니다. 물론 15일 간격은 에폭 날짜 이후 일관됩니다.
특히 UTC와의 수치 차이를 추가/감산하여 비슷하게 수치적으로 조정할 수 있는 집계 출력의 다른 시간대에 대해 시간을 조정하려면 "Math" 방법을 사용하는 것이 좀 더 쉽게 조정할 수 있습니다.
물론 그것은 좋은 해결책입니다.이 외에도 날짜를 날짜별로 문자열로 그룹화하거나(응답이 제안하는 대로) 날짜 필드를 투영하여(집약에서) 날짜의 시작을 가져올 수 있습니다.
{'$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")
}
여기에는 몇 가지 장점이 있습니다.날짜 유형(숫자나 문자열이 아님)으로 조작할 수 있습니다.다음 집약 조작에서 모든 날짜 집계 연산자를 사용할 수 있으며 출력에 날짜 유형을 제공합니다.
언급URL : https://stackoverflow.com/questions/5168904/group-by-dates-in-mongodb
'programing' 카테고리의 다른 글
mongoose 스키마에 created_at 및 updated_at 필드 추가 (0) | 2023.03.31 |
---|---|
React JS: "Uncatched Syntax Error:예기치 않은 토큰 <" (0) | 2023.03.31 |
"ErrorUtils caughed error" - Wordpress Facebook 플러그인에서 Chrome 콘솔 오류 발생 (0) | 2023.03.31 |
MongoDB Compass 툴에서 업데이트($set) 쿼리를 실행하는 방법 (0) | 2023.03.31 |
열의 마지막 세 문자를 기준으로 정렬할 쿼리 (0) | 2023.03.31 |