2017-03-05 11 views
2

が含まれている場合、私は、ドキュメントを次ていますMongoDBの集計プロジェクトのチェック配列が

{ 
    _id : 21353456, 
    username : "xy", 
    text : "asdf", 
    comments : [ 
     { 
      username : "User1", 
      text : "hi", 
     }, 
     { 
      username : "User2", 
      text : "hi1", 
     }, 
     { 
      username : "User3", 
      text : "hi2", 
     }, 
     { 
      username : "User4", 
      text : "hi3", 
     } 

    ] 
} 

を今私が集約し、プロジェクトに、ユーザー名、テキストやコメントを取得したいです。また、コメント配列に "User1"のユーザー名が含まれている場合は、論理値が必要です。私はこれを持っているが、うまくいかない。あなたが最初unwindにコメントを必要とし、その後、少しトリックでgroupを使用することになり、これを達成するために

db.posttest.aggregate(
    [ 
    { 
     $project: 
      { 
      username: 1, 
      text: 1, 
      comments : 1, 
      hasComment: { $eq: [ "comments.$.username", "User1" ] }, 
      _id: 0 
      } 
    } 
    ] 
) 

答えて

3

_idを省略したい場合は、シンプルなプロジェクトも行う必要があります。ここに完全な集約パイプラインがあります:

db.posttest.aggregate([ 
    { $unwind : "$comments" }, 
    { $group : { 
    _id : "$_id", 
    username : { $first : "$username" }, 
    text : { $first : "$text" }, 
    comments : { $push : "$comments" }, 
    hasComments : { $max : { $eq : [ "$comments.username", "User1" ] } } 
    }}, 
    { $project : { _id : false } } 
]) 

説明は次のとおりです。

まず、配列(comments)を取り除く必要があります。これを行うには、レコードを巻き戻します。

{ 
    "_id" : 21353456, 
    "username" : "xy", 
    "text" : "asdf", 
    "comments" : { 
    "username" : "User1", 
    "text" : "hi" 
    } 
}, 
{ 
    "_id" : 21353456, 
    "username" : "xy", 
    "text" : "asdf", 
    "comments" : { 
    "username" : "User2", 
    "text" : "hi1" 
    } 
}, 
{ 
    "_id" : 21353456, 
    "username" : "xy", 
    "text" : "asdf", 
    "comments" : { 
    "username" : "User3", 
    "text" : "hi2" 
    } 
}, 
{ 
    "_id" : 21353456, 
    "username" : "xy", 
    "text" : "asdf", 
    "comments" : { 
    "username" : "User4", 
    "text" : "hi3" 
    } 
} 

ここでは、すべてのレコードを1つにグループ化して、各フィールドに関数を適用することができます。まず、基準を与える必要があります。「グループ別」フィールド(またはフィールドセット)です。私たちの場合、それは単にid:_id: "$_id"です。

次に、フィールドごとに、それを結果のレコードに含める方法を決定する必要があります。フィールド数はusername,textcommentsです。 4つのレコードごとにユーザー名とテキストは同じですので、簡単に選択できます。すなわち、$firstまたは$lastです。

commentsしかし、異なります。私たちはそれらのすべてを保存して、$pushを1つずつ戻したいと思います。

hasCommentsはちょっと難しいです:少なくとも1つのユーザ名にユーザ名が含まれているかどうかを確認する必要があります。ここでは$eq: [...]を使用できます。 [true, false, false, false]または[false, false, true, false]。結果のレコードにどの値が入るかを選択する必要があります。この場合、$first$lastも使用できません。しかし、$maxは適切な結果を与えます。

+2

ありがとう、素晴らしい答え! – user6586661

0

お試しできる代替オプションがいくつかあります。そうでなければ0 falseよりサイズGT場合に発生し、trueのプロジェクトブール値の何をカウントする$size続いないusernameUser1

最初のオプション$filtercommentsのアレイ。

db.posttest.aggregate(
    [{ 
     $project: { 
      username: 1, 
      text: 1, 
      comments: 1, 
      hasComment: { 
       $gt: [{ 
        $size: { 
         $filter: { 
          input: "$comments", 
          as: "comment", 
          cond: { 
           $eq: ["$$comment.username", "User1"] 
          } 
         } 
        } 
       }, 0] 
      }, 
      _id: 0 
     } 
    }] 
) 

第2のオプションは、usernameUser1を持つ配列がcommentsアレイ内usernameの配列値のサブセットであるかどうかを確認する$setIsSubset集合演算子を使用することです。

db.posttest.aggregate(
    [{ 
     $project: { 
      username: 1, 
      text: 1, 
      comments: 1, 
      hasComment: { 
       $setIsSubset: [ 
        ["User1"], "$comments.username" 
       ] 
      }, 
      _id: 0 
     } 
    }] 
)