2016-04-19 10 views
2

MongoDBのクエリ/集計が必要:配列がある場合、配列の異なる値に応じてドキュメントをグループ化するにはどうすればよいですか?例:アレイ内の異なるオブジェクトの値はグループ化されていますか?

私は、これらのオブジェクトがある場合:

> db.respondents.insert({person: 1, responses: [{question: 'How old are you?', response: '18-40 yrs'}, {question: 'What is the brand of your car?', response: 'Fiat'} ] }) 
> db.respondents.insert({person: 2, responses: [{question: 'How old are you?', response: '18-40 yrs'}, {question: 'What is the brand of your car?', response: 'Volvo'} ] }) 
> db.respondents.insert({person: 3, responses: [{question: 'How old are you?', response: '41-65 yrs'}, {question: 'What is the brand of your car?', response: 'Volvo'} ] }) 
> db.respondents.insert({person: 4, responses: [{question: 'How old are you?', response: '41-65 yrs'}, {question: 'What is the brand of your car?', response: 'Volvo'} ] }) 

をそして、何の車のブランドの回答者の年齢グループ(別名内訳の質問)あたり自身(別名ベースの質問に)私に語ったクエリを記述したいと思いますか?

だから、答えは私に教えてください:

1人の年齢層'18 -40' あなたの車のブランドは何ですか 『質問する『フィアットを答え』』?年齢層'18で

1人が-40' ボルボはあなたの車のブランドは何ですか 『疑問を『答え』?』

'41 -65 'の年齢層の2人が'あなたの車のブランドは何ですか?

そしてIRL:

  • 100.000+回答
  • がある回答者あたり約30 'の応答は'
  • ありMongoDBの3.0.9

を使用している私が試してみました数多くの方法がありますが、私の失敗であなたを退屈させません....

答えて

3

$arrayElemAtと​​などの事業者が、この単一$group段階で単純なプロセス作るので、それは、あなたがMongoDBの3.2を持っていないピティーです:あなたがコンテンツを$unwindする必要があります以前のバージョンでは

db.respondents.aggregate([ 
    { "$match": { 
    "responses.question": { 
     "$all": [ 
     "How old are you?", 
     "What is the brand of your car?" 
     ] 
    } 
    }}, 
    { "$group": { 
    "_id": { 
     "age": { 
     "$arrayElemAt": [ 
      { "$map": { 
      "input": { "$filter": { 
       "input": "$responses", 
       "as": "res", 
       "cond": { 
       "$eq": [ "$$res.question", "How old are you?" ] 
       } 
      }}, 
      "as": "res", 
      "in": "$$res.response" 
      }}, 
      0 
     ] 
     }, 
     "car": { 
     "$arrayElemAt": [ 
      { "$map": { 
      "input": { "$filter": { 
       "input": "$responses", 
       "as": "res", 
       "cond": { 
       "$eq": [ "$$res.question", "What is the brand of your car?" ] 
       } 
      }}, 
      "as": "res", 
      "in": "$$res.response" 
      }}, 
      0 
     ] 
     } 
    }, 
    "count": { "$sum": 1 } 
    }} 
]) 

db.respondents.aggregate([ 
    { "$match": { 
    "responses.question": { 
     "$all": [ 
     "How old are you?", 
     "What is the brand of your car?" 
     ] 
    } 
    }}, 
    { "$unwind": "$responses" }, 
    { "$match": { 
    "responses.question": { 
     "$in": [ 
     "How old are you?", 
     "What is the brand of your car?" 
     ] 
    } 
    }}, 
    { "$group": { 
    "_id": "$_id", 
    "age": { 
     "$max": { 
     "$cond": [ 
      { "$eq": [ "$responses.question", "How old are you?" ] }, 
      "$responses.response", 
      null 
     ] 
     } 
    }, 
    "car": { 
     "$max": { 
     "$cond": [ 
      { "$eq": [ "$responses.question", "What is the brand of your car?" ] }, 
      "$responses.response", 
      null 
     ] 
     } 
    } 
    }}, 
    { "$group": { 
    "_id": { 
     "age": "$age", 
     "car": "$car" 
    }, 
    "count": { "$sum": 1 } 
    }} 
]) 
をしかし、もちろん、それは非常にPOSSです:その後、条件付き $condを経由して、必要な応答値を選択します一般的な結果は次のとおりです。

{ "_id" : { "age" : "41-65 yrs", "car" : "Volvo" }, "count" : 2 } 
{ "_id" : { "age" : "18-40 yrs", "car" : "Volvo" }, "count" : 1 } 
{ "_id" : { "age" : "18-40 yrs", "car" : "Fiat" }, "count" : 1 } 
+0

私はここでSOのコメントのガイドラインを無視して書いています:+1、ありがとう - あなたは私のヒーローです!甘味。まさに私が達成しようとしていたもの。 –

+0

すみません、もちろん「ヒロイン」を意味します。私はそれが昨日の月明かりではないと確信しました。 –

1

私は単純ですそれを行う方法。しかし! あなたがこれを行うことがあります。

db.respondents.aggregate([ 
    {$unwind:'$responses'}, 
    {$match:{'responses.question':'How old are you?'}} 
]).foreach(function(resp){ 
    db.responses.update({_id:resp._id},{$set:{ageGroup:resp.responses.response}}); 
}) 

それはいくつかの時間のために働く可能性がありますが、あなたは便利ageGroupフィールドを持っており、グループ化のためにそれを使用します。

+1

もちろん、他のコレクションにデータを書き込む必要はありません。現代版の方が効率的ではるかに効率的ですが、複数のクエリーやクライアントのループがなくても、どのバージョンでも実行できます。 –

関連する問題