복붙노트

[MONGODB] MongoDB의에서 날짜별로 그룹화

MONGODB

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"
}

난 주제에 클릭 그룹 번호에 원하는 : 내가 아는 .. (15 일 동안) 일까지 ABC 방법 그룹에 해당하지만 내가 어떻게 내 데이터베이스에 저장된 날짜별로 그룹

나는 다음과 같은 형식으로 결과를 찾고 있어요

[
  {
    "date" : "date in log",
    "click" : 9 
  },  
  {
    "date" : "date in log",
    "click" : 19
  },  
]

내가 코드를 작성했지만 그것은 날짜가 문자열에있는 경우에만 작동합니다 (코드는 여기에 http://pastebin.com/2wm1n1ix) ... 어떻게 그룹 그것을 나를 인도 해주십시오

해결법

  1. ==============================

    1.이 질문은 질문과 10gen 지금 쿼리 이런 종류의 작업을 수행 할 수있는 더 좋은 방법 인 통합 프레임 워크와 MongoDB를 버전 2.2을 발표, 대답 후. 당신이 날짜를 기준으로 그룹화 할 저장 값이 타임 스탬프 있기 때문에 당신이 일치하는 날짜에 타임 스탬프를 변환하기 위해 뭔가를해야하므로이 쿼리는 조금, 도전하고있다. 예제의 목적을 위해 나는 다만 적당한 수를 유도 할 수있는 쿼리를 작성합니다.

    이 질문은 질문과 10gen 지금 쿼리 이런 종류의 작업을 수행 할 수있는 더 좋은 방법 인 통합 프레임 워크와 MongoDB를 버전 2.2을 발표, 대답 후. 당신이 날짜를 기준으로 그룹화 할 저장 값이 타임 스탬프 있기 때문에 당신이 일치하는 날짜에 타임 스탬프를 변환하기 위해 뭔가를해야하므로이 쿼리는 조금, 도전하고있다. 예제의 목적을 위해 나는 다만 적당한 수를 유도 할 수있는 쿼리를 작성합니다.

    db.col.aggregate(
       { $group: { _id: { $dayOfYear: "$date"},
                   click: { $sum: 1 } } }
       )
    

    이 같은를 반환합니다 :

    [
        {
            "_id" : 144,
            "click" : 165
        },
        {
            "_id" : 275,
            "click" : 12
        }
    ]
    

    당신은 당신이 관심있는 날짜 범위 및 날짜에 _id 이름을 변경할 $ 프로젝트에 쿼리를 제한하는 $ 일치를 사용해야합니다. 당신이 변환 방법 최신 년 뒤의 일이 독자들에게 운동으로 남아 있습니다. :-)

    10gen은 몽고 집계 변환 차트 가치가 즐겨 찾기에 편리한 SQL을 가지고있다. 날짜 집계 연산자에 대한 특정 기사도 있습니다.

    조금 애호가를 얻기, 당신은 사용할 수 있습니다 :

    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} }
    ])
    

    하는 당신에게 최신 십오일을 얻고 날짜 필드에 매일 내에서 일부 날짜를 반환합니다. 예를 들면 :

    [
        {
            "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")
        }
    ]
    
  2. ==============================

    2.늦은 대답은하지만 (이 페이지에 관해서 다른 사람에 대한) 기록을 위해 : 키가 실제로의 날짜의 함수가 될 것입니다 때문에 당신은 대신에 '키'의 'keyf'인수를 사용해야합니다 이벤트 (즉, 날짜에서 추출 된 "일")이 아닌 날짜 자체. 이것은 당신이 찾고있는 무엇을 수행해야합니다

    늦은 대답은하지만 (이 페이지에 관해서 다른 사람에 대한) 기록을 위해 : 키가 실제로의 날짜의 함수가 될 것입니다 때문에 당신은 대신에 '키'의 '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++;}
    });
    

    http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group 자세한 내용은 집계 및 그룹에 MongoDB를의 문서 페이지를 살펴

  3. ==============================

    3.이 캔 도움말

    이 캔 도움말

    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);
    }
    
  4. ==============================

    4.이이 질문에 많은 답변은 이미,하지만 난 그들 중 만족하지 않았다. MongoDB를 수년에 걸쳐 개선, 그리고 그것을 할 지금 쉬운 방법이있다. 조나스 Tomanga에 의한 대답은 바로 그것을 얻을 수 있지만, 조금 너무 복잡하다.

    이이 질문에 많은 답변은 이미,하지만 난 그들 중 만족하지 않았다. MongoDB를 수년에 걸쳐 개선, 그리고 그것을 할 지금 쉬운 방법이있다. 조나스 Tomanga에 의한 대답은 바로 그것을 얻을 수 있지만, 조금 너무 복잡하다.

    당신이 MongoDB를 3.0 이상을 사용하는 경우 여기에 어떻게 당신이 할 수있는 그룹은 날짜입니다. 저자는 또한 결과를 제한하는 방법을 묻는 때문에 나는 $ 일치 집계로 시작합니다.

    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} }
    ])
    
  5. ==============================

    5.나는 완전하게 확신 때문에, 아직 MongoDB를 가진 많은 것을 일을하지 않았습니다. 하지만 당신은 전체 자바 스크립트를 사용할 수 없습니다? 당신은 자바 스크립트 날짜 클래스 날짜를 구문 분석 할 수 있도록,에 "밖으로"속성으로 키 등의 설정 중 하루 동안 데이트를 만들 수 있습니다. 키가 이미 존재하는 경우 항상 값 = 1 (첫 번째 클릭) 새로운 그렇지 않으면를 생성, 하나를 추가 할 수 있습니다. 다음은 기능 감소 적응하여 코드 (테스트되지 않은 코드를!)

    나는 완전하게 확신 때문에, 아직 MongoDB를 가진 많은 것을 일을하지 않았습니다. 하지만 당신은 전체 자바 스크립트를 사용할 수 없습니다? 당신은 자바 스크립트 날짜 클래스 날짜를 구문 분석 할 수 있도록,에 "밖으로"속성으로 키 등의 설정 중 하루 동안 데이트를 만들 수 있습니다. 키가 이미 존재하는 경우 항상 값 = 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"}
    }
    )
    
  6. ==============================

    6.또 다른 늦게 대답,하지만 여전히. 당신은 날짜와 다음과 같은 코드를 사용할 수 있습니다 주제별로 그룹화 클릭 수를 하나 개의 반복에서 그것을 얻을 싶어 그래서 경우 :

    또 다른 늦게 대답,하지만 여전히. 당신은 날짜와 다음과 같은 코드를 사용할 수 있습니다 주제별로 그룹화 클릭 수를 하나 개의 반복에서 그것을 얻을 싶어 그래서 경우 :

    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++; }
     })
    

    내 예제 속도가 동일하지만, 대신 문자열의 주요 날짜, 사용 valueOf () : 제안 쿼리를 최적화하고 싶은 또한 경우에 당신은 날짜에 대한 정수 값 (힌트를 사용할 수 있습니다.

    또한 그들이 새로운 기능을 모든 시간을 계속 추가하기 때문에, 정기적으로 MongoDB를 워드 프로세서를 확인하는 것이 현명하다. 당신이 훨씬 쉽게 http://docs.mongodb.org/manual/applications/aggregation/ 동일한 결과를 얻을 수 있습니다 2.2 버전에서 출시 될 새 집계 프레임 워크와 예를 들어,

  7. ==============================

    7.덕분에 @mindthief에 대한 답변 도움이 오늘 내 문제를 해결한다. 하루 캔 그룹 아래의 기능을 좀 더 쉽게, 희망은 다른 사람을 도울 수 있습니다.

    덕분에 @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'})
    
  8. ==============================

    8.MongoDB의 날짜하여 데이터 그룹을 가져올 수

    MongoDB의 날짜하여 데이터 그룹을 가져올 수

    db.getCollection('supportIssuesChat').aggregate([
    {
            $group : {
               _id :{ $dateToString: { format: "%Y-%m-%d", date: "$createdAt"} },
               list: { $push: "$$ROOT" },
               count: { $sum: 1 }
            }
    }
    ])
    
  9. ==============================

    9.그리고 대신 날짜 집계 연산자를 적용하는 대신 날짜 객체를 반올림 "날짜 수학"을 적용한다. 모든 드라이버가 일반적으로 그것이 가능한 모든 언어에 대한 날짜 조작에 사용되는 형태의 BSON 날짜를 나타냅니다 이것은 종종 바람직 할 수있다 :

    그리고 대신 날짜 집계 연산자를 적용하는 대신 날짜 객체를 반올림 "날짜 수학"을 적용한다. 모든 드라이버가 일반적으로 그것이 가능한 모든 언어에 대한 날짜 조작에 사용되는 형태의 BSON 날짜를 나타냅니다 이것은 종종 바람직 할 수있다 :

    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 일 "버킷"라는 질문에 암시 또는, 단순히 $ 모드에서 숫자 값에 그것을 적용하는 경우 :

    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 }
        }}
    ])
    

    적용되는 기본적인 수학은 $ 두 기간을 뺄 때하는 수치 differnce의 밀리 세컨드 될 것입니다 반환 된 결과를 객체이다. 시대는 당신이 어떤 언어 생성자의 변환을위한 거점으로 날짜 (0)로 표시되도록.

    수치로, "모듈"($ 개조)는 필요한 간격 (나눗셈에서 나머지를 감산) 날짜 라운드에 적용된다. 하나가되는 :

    또는

    그것은 유연 그래서 당신이 무엇을 필요로 간격.

    는 "숫자"값과 조합 된 두 개체의 millseconds 값 Date 객체 당량 반환 날짜 오브젝트 (에포크는 따라서 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의 숫자 차이를 뺀 / 추가하여 조정할 수 있습니다 집계 출력에서 ​​서로 다른 시간대에 대한 기간을 조정하려는 특히, 조정에 조금 더 쉽습니다.

  10. ==============================

    10.물론, 그건 좋은 솔루션입니다. 이외에도 당신은 문자열로 일하여 그룹 날짜 (즉, 답변으로는 제안) 할 수있는 나 당신이 그런 식으로 (집계)에 날짜 필드를 투영하여 날짜의 시작을 얻을 수 있습니다 :

    물론, 그건 좋은 솔루션입니다. 이외에도 당신은 문자열로 일하여 그룹 날짜 (즉, 답변으로는 제안) 할 수있는 나 당신이 그런 식으로 (집계)에 날짜 필드를 투영하여 날짜의 시작을 얻을 수 있습니다 :

    {'$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")
    }
    

    그것은 약간의 흑자를 가지고 : 당신이 날짜 형식 (안 숫자 또는 문자열)에있는 당신의 일에 조작 할 수 있습니다, 당신이 집계 작업을 다음 날짜 집계 사업자 모두 사용할 수 있으며, 출력에 당신에게 날짜 형식을 제공합니다.

  11. from https://stackoverflow.com/questions/5168904/group-by-dates-in-mongodb by cc-by-sa and MIT license