2016-03-29 5 views
1

集計$ルックアップを使用して2つ以上のフィールドを2つのコレクションに結合する必要があります。参加することは可能ですか?可能であれば教えてください。ここで私は2つのコレクションを持っています:

例: "people"コレクションフィールド "country"コレクションフィールド "city_id、state_id、country_id"のフィールド "city_id、state_id、country_id"、次のコレクションのこの3つのフィールドに参加したい。

「ピープル」

{  
     "_id" : 1, 
     "email" : "[email protected]", 
     "userId" : "AD", 
     "userName" : "admin", 
     "city" : 1, 
     "state" : 1, 
     "country" : 1 
    } 

「国」

 { 
     "country_id" : 1, 
     "userId" : "AD", 
     "phone" : "0000000000", 
     "stateinfo":[{ 
      "state_id" : 1, 
      "state_name" : "State1" 
     },{ 
      "state_id" : 2, 
      "state_name" : "State2" 
     } 
     ], 
     "cityinfo":[{ 
      "city_id" : 1, 
      "city_name" : "city1" 
     },{ 
      "city_id" : 2, 
      "city_name" : "city2" 
     } 
     ] 
    } 
+0

これらのコレクションは、PHPまたはmongoにありますか? – Chris

+0

@chris – Suresh

答えて

1

これはもちろん、「3」のすべてのフィールドが中に含まれていることを考えると、おそらくあなたが思うよりも多くの簡単です1 "country"文書。つまり、$lookup"country_id"で実行し、取得したコンテンツを使用して他のフィールドにデータを入力するだけです。配列は$lookupによってでマッチングされた後

{  
    "_id" : 1, 
    "email" : "[email protected]", 
    "userId" : "AD", 
    "userName" : "admin", 
    "country" : { 
    "country_id" : 1, 
    "userId" : "AD", 
    "phone" : "0000000000", 
    "stateinfo": { 
     "state_id" : 1, 
     "state_name" : "State1" 
    }, 
    "cityinfo": { 
     "city_id" : 1, 
     "city_name" : "city1" 
    } 
} 

だからそれがすべての最初の試合を取得するためにmatcingを行うために​​を使用して$arrayElemAtにダウンしています:のようにあなたに結果を与える必要があります

var pipeline = [ 
    { "$lookup": { 
    "from": "country", 
    "localField": "country", 
    "foreignField": "country_id", 
    "as": "country" 
    }}, 
    { "$project": { 
    "email": 1, 
    "userId": 1, 
    "userName": 1, 
    "country": { 
     "$arrayElemAt": [ 
     { "$filter": { 
      "input": { 
      "$map": { 
       "input": "$country", 
       "as": "country", 
       "in": { 
       "country_id": "$$country.country_id", 
       "userId": "$$country.userId", 
       "phone": "$$country.phone", 
       "stateInfo": { 
        "$arrayElemAt": [ 
        { "$filter": { 
         "input": "$$country.stateInfo", 
         "as": "state", 
         "cond": { "$eq": [ "$$state.state_id", "$state" ] } 
        }}, 
        0 
        ] 
       }, 
       "cityinfo": { 
        "$arrayElemAt": [ 
        { "$filter": { 
         "input": "$$country.cityinfo", 
         "as": "city", 
         "cond": { "$eq": [ "$$city.city_id", "$city" ] } 
        }}, 
        0 
        ] 
       } 
       } 
      } 
      }, 
      "as": "country", 
      "cond": { "$eq": [ "$$country.userId", "$userId" ] } 
     }}, 
     0 
     ] 
    } 
    }} 
] 

db.people.aggregate(pipeline) 

フィルタリングされた各配列。

外側の配列には「内側」の配列があるため、「外側」のソースには$mapを使用し、それぞれの「内側」配列には​​を適用します。

$letを使用すると、「縮小」された配列の内容を返されたサブ文書に変換し、その結果のプロパティを参照するだけで、より平坦な応答を得ることができますが、配列要素は上記と同じままである。 PHPの構造変換に

$pipeline = array(
    array(
    '$lookup' => array(
     'from' => 'country', 
     'localField' => 'country' 
     'foreignField' => 'country_id', 
     'as' => 'country' 
    ) 
) 
    array(
    '$project' => array(
     'email' => 1, 
     'userId' => 1, 
     'userName' => 1, 
     'country' => array(
     '$arrayElemAt' => array(
      array(
      '$filter' => array(
       'input' => array(
       '$map' => array(
        'input' => '$country', 
        'as' => 'country', 
        'in' => { 
        'country_id' => '$$country.country_id', 
        'userId' => '$$country.userId', 
        'phone' => '$$country.phone', 
        'stateInfo' => array(
         '$arrayElemAt' => array(
         array(
          '$filter' => array(
          'input' => '$$country.stateInfo', 
          'as' => 'state', 
          'cond' => array('$eq' => array('$$state.state_id', '$state')) 
         ) 
         ), 
         0 
        ) 
        ), 
        'cityinfo' => array(
         '$arrayElemAt' => array(
         array(
          '$filter' => array(
          'input' => '$$country.cityinfo', 
          'as' => 'city', 
          'cond' => array('$eq' => array('$$city.city_id', '$city')) 
         ) 
         ), 
         0 
        ) 
        ) 
        } 
       ) 
      ), 
       'as' => 'country', 
       'cond' => array('$eq' => array('$$country.userId', '$userId')) 
      ) 
     ), 
      0 
     ) 
    ) 
    ) 
) 
); 

$people->aggregate($pipeline); 

あなたは通常、あなたがパイプライン構造をダンプすることでJSONの例から作業しているとき、あなたのPHPは、JSONの構造と一致して確認することができます。

echo json_encode($pipeline, JSON_PRETTY_PRINT) 

そして、それあなたは間違って行くことはできません。

ここで別の最後の注意として、$lookupの後のプロセスは、非常に効率的であっても非常に「複雑」です。だから、私は、この集約パイプラインをさらに活用し、実際に何かを集約する必要がなければ、サーバー上で行うのではなく、クライアントコードでその「フィルタリング」を行うほうがよいでしょう。

同じことをするクライアントコードは、集約パイプラインに行うために必要なものよりはるかに「鈍い」です。したがって、実際には、一致した配列を減らすことで帯域幅の使用量を大幅に節約できない場合や、代わりに別のクエリを実行してコードを実行したり、別のクエリを実行したりすることができます。

関連する問題