2015-11-15 156 views
2

使用從蒙戈文檔的例子中的一個子集:我如何返回調查12345(不管即使它有調查與否)Mongo的查詢只返回子文檔

{ _id: 1, results: [ { product: "abc", score: 10 }, { product: "xyz", score: 5 } ] } 
{ _id: 2, results: [ { product: "abc", score: 8 }, { product: "xyz", score: 7 } ] } 
{ _id: 3, results: [ { product: "abc", score: 7 }, { product: "xyz", score: 8 } ] } 

db.survey.find(
    { id: 12345, results: { $elemMatch: { product: "xyz", score: { $gte: 6 } } } } 
) 

只有收益調查分數大於6?換句話說,我不希望文檔從基於子文檔的結果中取消資格,我想要文檔但只有一部分子文檔。

+0

因此,在所有情況下都要返回文檔,但要過濾數組內容?那麼所有的文檔都會返回,但只有符合條件的數組成員纔會返回。正確? –

+0

是的,就像SQL中的左連接一樣 –

回答

1

您可以使用$纂這樣:

db.survey.aggregate([ 
 
    { $match : { _id : 12345 }}, 
 
    { $redact: { 
 
    $cond: { 
 
     if: { 
 
      $or: [ 
 
      { $eq: [ "$_id", 12345 ] }, 
 
      { $and: [ 
 
       { $eq: [ "$product", "xyz" ] }, 
 
       { $gte: [ "$score", 6 ] } 
 
      ]} 
 
      ] 
 
     }, 
 
     then: "$$DESCEND", 
 
     else: "$$PRUNE" 
 
     } 
 
    } 
 
    } 
 
]);

它將由_id $比賽:12345第一,然後它會 「$$剪枝」 所有的子文檔,唐」沒有得分大於或等於6.我添加了條件($ cond){$ eq:[「$ _id」,12345]},這樣它就不會修剪整個文檔在達到子文檔之前。

3

你所要求的不是一個「查詢」,而是基本上只是從每個文檔中的數組中過濾內容。

爲此,您可以.aggregate()$project

db.survey.aggregate([ 
    { "$project": { 
     "results": { 
      "$setDifference": [ 
       { "$map": { 
        "input": "$results", 
        "as": "el", 
        "in": { 
         "$cond": [ 
          { "$and": [ 
           { "$eq": [ "$$el.product", "xyz" ] }, 
           { "$gte": [ "$$el.score", 6 ] } 
          ]} 
         ] 
        } 
       }}, 
       [false] 
      ] 
     } 
    }} 
]) 

因此,而不是「contrain」結果有一個數組成員匹配,這一切都是在做條件文件被「過濾」陣列成員指出,不符合條件,但如果需要的話,返回帶有空數組的文檔。

目前最快的方法是用$map檢查所有元素,並且$setDifference過濾掉從該檢查返回的任何值false。可能的缺點是「集合」必須包含獨特的元素,所以只要元素本身是唯一的就可以了。

未來版本將具有$filter方法,其類似於在結構$map,而是直接刪除不匹配的結果,其中如$map只是返回它們(通過$cond,要麼匹配元件或false)並且隨後更適合。

否則,如果不是唯一的或者MongoDB服務器版本低於2.6,你這樣做是使用$unwind,在非性能方法:

db.survey.aggregate([ 
    { "$unwind": "$results" }, 
    { "$group": { 
     "_id": "$_id", 
     "results": { "$push": "$results" }, 
     "matched": { 
      "$sum": { 
       "$cond": [ 
        { "$and": [ 
         { "$eq": [ "$results.product", "xyz" ] }, 
         { "$gte": [ "$results.score", 6 ] } 

        ]}, 
        1, 
        0 
       ] 
      } 
     } 
    }}, 
    { "$unwind": "$results" }, 
    { "$match": { 
     "$or": [ 
      { 
       "results.product": "xyz", 
       "results.score": { "$gte": 6 } 
      }, 
      { "matched": 0 } 
    }}, 
    { "$group": { 
     "_id": "$_id", 
     "results": { "$push": "$results" }, 
     "matched": { "$first": "$matched" } 
    }}, 
    { "$project": { 
     "results": { 
      "$cond": [ 
       { "$ne": [ "$matched", 0 ] }, 
       "$results", 
       [] 
      ] 
     } 
    }} 
]) 

這是在設計和性能比較相當可怕的。因此,您最好在客戶端代碼中對每個文檔進行過濾。

2

您可以使用$過濾器的MongoDB 3.2

db.survey.aggregate([{ 
     $match: { 
      { id: 12345} 
     } 
    }, { 
     $project: { 
      results: { 
       $filter: { 
        input: "$results", 
        as: "results", 
        cond:{$gt: ['$$results.score', 6]} 
       } 
      } 
     } 
    }]); 

它將返回如果你只想返回第一個匹配的文件比你可以使用具有分數大於6的所有子文件「$」操作。