2016-01-31 7 views
5

は、私は2つのモデルがあり、一つはユーザーmongooseで集計前に集計を使用することはできますか?

userSchema = new Schema({ 
    userID: String, 
    age: Number 
}); 

であり、他のスコアは私がいくつかのクエリ/計算をしたいと思っすべてのユーザー

ScoreSchema = new Schema({ 
    userID: {type: String, ref: 'User'}, 
    score: Number, 
    created_date = Date, 
    .... 
}) 

のために、日常に数回記録され、特定の要件を満たす一部のユーザーのスコア。たとえば、20日以上のすべてのユーザーのスコアの平均を計算したいとします。

私の思考まずは、ユーザーの年齢層を取り込むためにスコアにを移入し、その後集計を行うということです。

Score. 
    populate('userID','age'). 
    aggregate([ 
     {$match: {'userID.age': {$gt: 20}}}, 
     {$group: ...}, 
     {$group: ...} 
    ], function(err, data){}); 

のようなものは、それが集計前に移入使用するokですか?または、私はまず、要件を満たすすべてのuserIDを見つけて、配列に保存してから、$ inを使用してスコアドキュメントにマッチさせます。

答えて

8

ありませんあなたは.aggregate().populate()を呼び出すことはできません、と非常に良い理由がなぜあなたがすることはできませんです。しかし、あなたが取ることができるさまざまなアプローチがあります。

.populate()メソッドは、参照されているコレクションから指定された要素を「参照」するために、基礎となるコードが実際に追加のクエリ(正確には$inクエリ)を実行する「クライアント側」で機能します。 は「サーバー側」操作なので、基本的にコンテンツ「クライアント側」を操作することはできず、後でそのデータを集約パイプラインステージで使用できるようにします。それはあなたが操作しているコレクションにすべて存在する必要があります。

ここで、MongoDB 3.2以降では、$lookupアグリゲーションパイプライン操作により、より良いアプローチが得られます。これは、基本的に新しいフィールドを含めるために起こっている

User.aggregate(
    [ 
     // Filter first 
     { "$match": { 
      "age": { "$gt": 20 } 
     }}, 
     // Then join 
     { "$lookup": { 
      "from": "scores", 
      "localField": "userID", 
      "foriegnField": "userID", 
      "as": "score" 
     }}, 
     // More stages 
    ], 
    function(err,results) { 

    } 
) 

項目の「アレイ」としてUserオブジェクト内の「スコア」:また、おそらく最高の選択を絞り込むために、この場合にUserコレクションから処理します

{ 
    "userID": "abc", 
    "age": 21, 
    "score": [{ 
     "userID": "abc", 
     "score": 42, 
     // other fields 
    }] 
} 

一般的な予想される使用が可能との関係「多くのものを」「左の参加」であるとして、結果は、常に配列である:それは、他のコレクションに「検索」に一致します。結果が一致しない場合は空の配列になります。

コンテンツを使用するには、何らかの方法で配列を操作してください。たとえば、今後の操作でアレイの単一の最初の要素を取得するために、$arrayElemAt演算子を使用することができます。そして、通常の埋め込みフィールドのようにコンテンツを使うことができます:

 { "$project": { 
      "userID": 1, 
      "age": 1, 
      "score": { "$arrayElemAt": [ "$score", 0 ] } 
     }} 

MongoDBをお持ちでない場合は、3。

// Match the user collection 
User.find({ "age": { "$gt": 20 } },function(err,users) { 

    // Get id list  
    userList = users.map(function(user) { 
     return user.userID; 
    }); 

    Score.aggregate(
     [ 
      // use the id list to select items 
      { "$match": { 
       "userId": { "$in": userList } 
      }}, 
      // more stages 
     ], 
     function(err,results) { 

     } 
    ); 

}); 

だから、のリストを取得することにより:使用可能な2、その後、別のコレクションの関係によって制限されたクエリを処理するために、あなたの他のオプションは、最初に、そのコレクションから結果を取得した後、第2にフィルタリングする$inを使用することです他のコレクションからクライアントへの有効なユーザーを取得し、それをクエリ内の他のコレクションに渡すことは、これを以前のリリースで実現するための一番の方法です。

+0

userListがobjectIdの配列である場合、文字列に変換する必要がありますか? –

+0

あなたはスマートな人間ですが、foriegnFieldはforeignFieldでなければなりません。大きな問題ではない –

関連する問題