2016-02-09 61 views
1

过滤数组元素的领域考虑下面的模式:

{ 
    "_id" : ObjectId("56b9bfb962debd68f8b61340"), 
    "Name" : "Parent", 
    "Children" : [ 
     { 
      "Name" : "A", 
      "Age" : NumberInt(0) 
     }, 
     { 
      "Name" : "B", 
      "Age" : NumberInt(1) 
     }, 
     { 
      "Name" : "C", 
      "Age" : NumberInt(2) 
     } 
    ] 
} 

我使用2 $项目阶段。 1过滤“孩子”,另一个选择除“Children.Age”字段:

db.collection.aggregate(
    [ 
    { 
     $project: { 
     Name: 1, 
     Children: { $filter: { 
      input: "$Children", 
      as: "child", 
      cond: { $gt: ["$$child.Age", 0] } 
     } } 
     } 
    }, 
    { 
     $project: { 
     Name: 1, 
     Children: { Name: 1 } 
     } 
    } 
    ] 
); 

我能做到只用1 $项目的阶段呢?

我想避免使用$ unwind和$组,如果可能的话。

回答

1

是的,你可以缩短你的管道到一个阶段。要做到这一点,您需要使用$map运营商。

db.collection.aggregate([ 
    { "$project": { 
     "Name": 1, 
     "children": { 
      "$map": { 
       "input": { 
        "$filter": { 
         "input": "$Children", 
         "as": "child", 
         "cond": { "$gt": [ "$$child.Age", 0 ] } 
        } 
       }, 
       "as": "ch", 
       "in": 
       "$$ch.Name" 
      } 
     } 
    }} 
]) 

另一种替代方法是使用$setDifference操作者和操作者$map操作者。但正如文档中提到的:

$setDifference在结果中过滤出重复项以输出仅包含唯一项的数组。

db.collection.aggregate([ 
    { "$project": { 
     "Name": 1, 
     "Children": { 
      "$setDifference": [ 
       { "$map": { 
        "input": "$Children", 
        "as": "child", 
        "in": { 
         "$cond": [ 
          { "$gt": [ "$$child.Age", 0 ] }, 
          "$$child.Name", 
          false 
         ] 
        } 
       }}, 
       [false] 
      ] 
     } 
    }} 
]) 

它返回:

{ 
     "_id" : ObjectId("56b9bfb962debd68f8b61340"), 
     "Name" : "Parent", 
     "Children" : [ 
       "B", 
       "C" 
     ] 
} 
+0

在第一解决方案:如果我whant排除1个领域,包括至少2个字段? –