2014-06-19 3 views
5

mongodb 집계를 사용하여 데이터 집합을 집계하고 있습니다. 내 상황이 좀 복잡해. 나는 다음과 같은 컬렉션을했습니다 : 일 및 시간별 몽고드 집계

{ 
    startTime: ISODate("2014-12-31T10:20:30Z"), 
    customerId: 123, 
    ping: "2", 
    link: "3" 
} 

지금 나는 다음과 같은 다른 컬렉션에 데이터를 집계 할 :

{ 
_id: { 
day: ISODate("2014-12-31T00:00:00Z"), 
customerId: 123 
}, 
hours: [ 
    { 
    hour: ISODate("2014-12-31T10:00:00Z"), 
    pings: 2, 
    links: 3 
    }, 
    { 
    hour: ISODate("2014-12-31T11:00:00Z"), 
    pings: 5, 
    links: 6 
    } 
] 
} 

하면 데이터가 시간에 의해 처음으로 다음 날까지 그룹입니다 볼 수 있듯이. 하루에 그룹화 할 수있는 집계 쿼리가 있지만 시간별로 그룹화하는 방법은 무엇입니까? 어떤 아이디어?

var pipeline = [ 
{ 
$project : { 
     startTime : 1, 
       customerId: 1, 
     ping:1, 
     link:1, 
     date : "$startTime", 
     h : { 
      "$hour" : "$startTime" 
     }, 
     m : { 
      "$minute" : "$startTime" 
     }, 
     s : { 
      "$second" : "$startTime" 
     }, 
     ml : { 
      "$millisecond" : "$startTime" 
     } 
    } 
}, 
{ 
$project: { 
    startTime : 1, 
      customerId: 1, 
    ping:1, 
    link:1, 
     date : {  
      "$subtract" : [  
       "$date",  
       {  
         "$add" : [  
          "$ml",  
          {  
           "$multiply" : [  
            "$s",  
            1000  
           ]  
          },  
          {  
           "$multiply" : [  
            "$m",  
            60,  
            1000  
           ]  
          }, 
          {  
           "$multiply" : [  
            "$h",  
            60,  
            60,  
            1000 
           ]  
          }  
         ]  
       }  
      ]  
     } 
    }   
}, 
{ 
    $match: { 
     "startTime": { 
      $gte: new ISODate("2013-12-01T07:00:00Z"), 
      $lte: new ISODate("2014-01-01T08:00:00Z"), 
     } 
    } 
}, 
// Aggregate the data 
{ 
    $group: { 
     _id: {day : "$date", customerId: "$customerId"}, 
     pings : {$sum: "$ping"}, 
     links : {$sum: "$links"} 
    } 
} 
]; 

답변

7

은 당신이 기본적으로 원하는 것은 이중 그룹입니다,하지만 당신은 다시 단지 관련 부분의 date aggregation operators를 사용하여 전체 날짜 개체를 얻을하지 않습니다

db.collection.aggregate([ 
    { "$group": { 
     "_id": { 
      "customerId": "$customerId", 
      "day": { "$dayOfYear": "$startTime" }, 
      "hour": { "$hour": "$startTime" } 
     }, 
     "pings": { "$sum": "$ping" }, 
     "links": { "$sum": "$link" } 
    }}, 
    { "$group": { 
     "_id": { 
      "customerId": "$_id.customerId", 
      "day": "$_id.day" 
     }, 
     "hours": { 
      "$push": { 
       "hour": "$_id.hour", 
       "pings": "$pings", 
       "links": "$links" 
      } 
     } 
    }} 
]) 

이중 $group 당신에게주는 형식을 사용하여 원하는 결과를 배열에 저장할 수 있습니다. 단일 샘플에서 문서,하지만 당신은 기본적으로 같은 결과를 얻을 : 당신이 거래 또는 날짜 개체에 대한 단순화 된 "통과"결과를 원하는 어려운에 날짜 사업자의 결과를 검색 한 경우,

{ 
    "_id" : { 
      "customerId" : 123, 
      "day" : 365 
    }, 
    "hours" : [ 
      { 
        "hour" : 10, 
        "pings" : 2, 
        "links" : 3 
      } 
    ] 
} 

을 시대가 대신 타임 스탬프로 당신은 캐스팅 수 : 당신이 서로 $subtract 한 날짜 개체를 다시 결과로 "시대"값을 얻을 때이

db.collection.aggregate([ 
    { "$group": { 
     "_id": { 
      "customerId": "$customerId", 
      "day": { 
       "$subtract": [ 
        { "$subtract": [ "$startTime", new Date("1970-01-01") ] }, 
        { 
         "$mod": [ 
          { "$subtract": [ "$startTime", new Date("1970-01-01") ] }, 
          1000*60*60*24 
         ] 
        } 
       ] 
      }, 
      "hour": { 
       "$subtract": [ 
        { "$subtract": [ "$startTime", new Date("1970-01-01") ] }, 
        { 
         "$mod": [ 
          { "$subtract": [ "$startTime", new Date("1970-01-01") ] }, 
          1000*60*60 
         ] 
        } 
       ] 
      } 
     }, 
     "pings": { "$sum": "$ping" }, 
     "links": { "$sum": "$link" } 
    }}, 
    { "$group": { 
     "_id": { 
      "customerId": "$_id.customerId", 
      "day": "$_id.day" 
     }, 
     "hours": { 
      "$push": { 
       "hour": "$_id.hour", 
       "pings": "$pings", 
       "links": "$links" 
      } 
     } 
    }} 
]) 

트릭에. 이 경우 우리는 "신기원"시작 날짜를 사용하여 전체 시간 소인 값을 얻고 "날짜 계산"을 제공하여 필요한 간격으로 시간을 수정합니다. 따라서 결과 :

{ 
    "_id" : { 
      "customerId" : 123, 
      "day" : NumberLong("1419984000000") 
    }, 
    "hours" : [ 
      { 
        "hour" : NumberLong("1420020000000"), 
        "pings" : 2, 
        "links" : 3 
      } 
    ] 
} 

귀하의 필요에 따라 운영자가 결과로 제공하는 것보다 더 편할 수 있습니다.

당신은 또한 당신이 범위의 작업에 대해 "변수"를 선언 할 수있는 $let 연산자를 통해 MongoDB를 2.6로 이것에 대한 약간의 속기를 추가 할 수 있습니다 또한

db.event.aggregate([ 
    { "$group": { 
     "_id": { 
      "$let": { 
       "vars": { 
        "date": { "$subtract": [ "$startTime", new Date("1970-01-01") ] }, 
        "day": 1000*60*60*24, 
        "hour": 1000*60*60 
       }, 
       "in": { 
        "customerId": "$customerId", 
        "day": { 
         "$subtract": [ 
          "$$date", 
          { "$mod": [ "$$date", "$$day" ] } 
         ] 
        }, 
        "hour": { 
         "$subtract": [ 
          "$$date", 
          { "$mod": [ "$$date", "$$hour" ] } 
         ] 
        } 
       } 
      } 
     }, 
     "pings": { "$sum": "$ping" }, 
     "links": { "$sum": "$link" } 
    }}, 
    { "$group": { 
     "_id": { 
      "customerId": "$_id.customerId", 
      "day": "$_id.day" 
     }, 
     "hours": { 
      "$push": { 
       "hour": "$_id.hour", 
       "pings": "$pings", 
       "links": "$links" 
      } 
     } 
    }} 
]) 

나는 거의 있음을 언급하는 것을 잊었다 "핑 (ping)에 대한 값 "및"link "는 오타가 아닌 한 실제로는 문자열입니다. 그러나 그렇지 않다면 먼저 숫자로 변환해야합니다.

+0

감사합니다. 좀 더 도와 주실 수 있나요? 나는 지난 시간의 데이터를 매 시간마다 실행하여'{ "_id": { "customerId": 123, "day": ISODate ("2012-06-20 : 00 : 00 : 00Z ")}, "시간 ": [{"시간 ": ISODate ("2012-06-20 : 01 : 00 : 00Z "),"핑 ": 2,"링크 ": 3}]}' 위의 집계 쿼리 실행 중, 집계 데이터를 저장하려면이 컬렉션에 병합/upsert해야합니다. 어떻게하면 될까요? 감사합니다 – user3756522

+0

@ user3756522 이것은 정말로 다른 질문처럼 들리며 의견보다는 의도를 올바르게 설명하는 새로운 게시물에 의해 가장 잘 제기됩니다. 답안에 표시된 검색어는 보내는 범위에 대해 매일 및 매시간 집계됩니다. 또한 이것에 대한'$ match'는 언제나 파이프 라인의 ** 첫 단계 **가되어야합니다. MongoDB 2.6을 사용하면 집계 출력은 결과를 처리하기 위해 반복하는 커서가 될 수 있습니다 –