2017-03-05 105 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", 
     } 

    ] 
} 

現在我想要得到的用戶名,文本和註釋採用聚集和項目。另外,如果comments數組包含用戶名「User1」,我也想要一個布爾值。我有這個,但它不起作用。

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

回答

3

要做到這一點,你需要先unwind的意見,然後用group有一個小竅門。如果你想省略_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" 
    } 
} 

現在我們可以將所有記錄組合成一個應用函數給每個字段。首先,我們需要給出標準,'分組'字段(或一組字段)。在我們的例子中,它僅僅是id:_id: "$_id"

然後,對於每個字段,我們需要決定如何將其包含到結果記錄中。我們有幾個字段:username,textcomments。對於每四條記錄,用戶名和文本都是相同的,因此我們可以輕鬆選取其中的任何一條,即$first$last

comments然而,是不同的。我們希望保留所有這些,以便我們每個人都退回$push

hasComments這裏有點棘手:我們需要檢查是否至少有一個comment.username包含用戶名。我們可以在這裏使用$eq: [...],它會給我們一些數組,例如[true, false, false, false][false, false, true, false]。我們需要選擇哪個值進入結果記錄。在這種情況下,我們既不能使用$first也不能使用$last。但是,$max會給我們一個合適的結果。

+2

謝謝,很好的回答! – user6586661

0

你有幾個可供選擇的選項,你可以嘗試。

第一個選項$filter小號comments陣列usernameUser1隨後$size計數沒有出現和true如果尺寸GT大於0別的false項目布爾值的。

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 
     } 
    }] 
) 

第二個選擇是使用$setIsSubset集合運算符來檢查是否陣列usernameUser1username列數組值的子集在comments陣列。

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