programing

mongodb로 날짜별로 분류하다

showcode 2023. 3. 31. 23:01
반응형

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

반응형