2016-08-18 1 views
3

내 문서는 다음과 같습니다그룹은 첫 번째 범주에 의해, 다음 주 또는 월 단위로

{ "$match" : { "timestamp" : { "$gt" : FROM , "$lt" : TO }}}, 
{ "$sort" : { "timestamp" : 1 }}, 
{ "$group" : { 
    "_id" : "$category", 
    "data" : { "$push" : { "timestamp" : "$timestamp" , "amount" : "$amount" }} 
}} 
:

이제
{ 
    category: "1", 
    timestamp: ISODate("2016-07-16T00:00:00.000Z"), 
    amount: 0 
}, 
{ 
    category: "1", 
    timestamp: ISODate("2016-08-18T00:00:00.000Z"), 
    amount: 15 
}, 
{ 
    category: "1", 
    timestamp: ISODate("2016-08-01T00:00:00.000Z"), 
    amount: 5 
}, 
{ 
    category: "2", 
    timestamp: ISODate("2016-08-18T00:00:00.000Z"), 
    amount: 10 
} 

I가 (이미 작동) 카테고리별로 그룹을 싶습니다

다음data 배열 내의 해당 개체를 그룹화합니다. 을 매주 최대 금액으로 받으려면 (또는 사용자 입력에 따라 달). (월별로 그룹화 할 때)

결과는 다음과 같이 보일 것이다 :

{ 
    _id: "1", 
    data: [ 
     { 
      timestamp: "2016-07", // could also be an ISODate with 
      amount: 0    // first (or last) day of month 
     },       // if that makes things easier 
     { 
      timestamp: "2016-08", 
      amount: 15 
     } 
    ] 
}, 
{ 
    _id: "2", 
    data: [ 
     { 
      timestamp: "2016-08", 
      amount: 10 
     } 
    ] 
} 

나는 unwinddata 배열을 시도하고 다시 그룹화,하지만 총 엉망 결과.

희망을 얻으려면이 멋진 아이디어/해결책이 필요합니다.

편집 : 추가 질문 :

나는 $match을 위해 잘 작동 category에 인덱스를 넣었습니다. 정렬을 위해 timestamp에 색인을 두는 것도 유용할까요? (삽입 순서가 타임 스탬프 순서와 다를 수 있기 때문입니다.) 아니면이 색인이 집계에 어떤 영향을 미치지 않을까요?

답변

2

저는 Styvane의 대답을 받았습니다 (다시 한번 감사드립니다!)과 조금 단순화 :

{$match: { timestamp: { $gt: FROM , $lt: TO }}}, 
{$group: { 
    _id: { 
     id: "$category", 
     timestamp: { $concat: [ 
      { $toLower: { $year:"$timestamp" } }, 
      "-", 
      { $toLower: { $month: "$timestamp" } } 
     ] } 
    }, 
    amount: { $max: "$amount" } 
}}, 
{$sort: { "_id.timestamp": 1 } }, 
{$group: { 
    _id: "$_id.id", 
    data: { $push: { timestamp: "$_id.timestamp", amount: "$amount" } } 
}} 

는 내가 처음 $group 전에 $sort에 노력하지만 때때로 예상치 못한 결과를 주셨 는가를. 방금 을 $group 단계 사이에 배치했지만 timestamp에 색인을 붙이는이 방법은 더 이상 상관 없습니다.

1

$sort 단계 이후에는 "카테고리"로 $group을 입력하고 "데이터"필드에는 $unwind을 입력해야합니다.

var group1 = { "$group": { 
    "_id": "$category", 
    "data": { 
     "$push": { 
      "timestamp": "$timestamp", 
      "amount": "$amount" 
     } 
    } 
}}; 

var unwind = { "$unwind": "$data"}; 

는 여기에서, 당신은 $group 문서를 다시해야하지만 이번에는 당신이뿐만 아니라 timestamp 필드하지만 _id 필드뿐만 아니라 고려할 필요하고 $toLower 운영자의 도움으로 당신은 올해로 변환 할 수 있습니다 $concat 연산자를 사용하여 연결할 수있는 문자열의 월 값입니다.

또한 $sum과 함께 해당 그룹의 합계를 반환합니다.

var group2 = { "$group": { 
    "_id": { 
     "id": "$_id", 
     "timestamp": { 
      "$concat": [ 
       { "$toLower": { "$year": "$data.timestamp" } }, 
       "-", 
       { "$toLower": { "$month": "$data.timestamp" } } 
      ] 
    }}, 
    "amount": { "$sum": "$data.amount" } 
}} 

마지막 단계는 단순히 그룹 이전 _id.id 값을 기준으로 문서 및 데이터의 배열을 반환 할 $push 누적 연산자를 사용하여 다른 $group 단계입니다.

var group3 = { "$group": { 
    "_id": "$_id.id", 
    "data": { 
     "$push": { 
      "timestamp": "$_id.timestamp", 
      "amount": "$amount" 
     } 
    } 
}}; 

귀하의 최종 파이프 라인은 다음과 같이 표시됩니다

db.collection.aggregate(
    [ 
     // $match and `$sort here 
     group1, 
     unwind, 
     group2, 
     group3 
    ] 
) 

이 쿼리는 MongoDB를의 향후 버전에서 개선 할 수있는 $facet 연산자를 사용하여.

db.collection.aggregate([ 
    // $match and `$sort here 
    { "$facet": { "data": [ group1, unwind, group2, group3 ] } 
]) 
+0

와우! 고맙습니다! 나중에 다시 시도해 보겠습니다. 정렬을 위해 타임 스탬프 필드에 색인을 만드는 것에 대한 의견이 있습니까? –

+0

코드를 기반으로 답변을 추가했습니다. group1과 unwind는 필요 없지만 컬렉션 자체에 그룹화를합니다. 그러나'$ match' 직후의'$ sort'는 예상 된 결과를 제공하지 못했습니다. 나는 이것을 설명 할 수 없다. 비록'$ sort'를'$ group' 단계 사이에 넣었습니다. –

관련 문제