如何在mongodb聚合输出中包括不匹配的文档?

时间:2020-03-01 16:03:13

标签: mongodb mongodb-query aggregation-framework

我在下面的聚合中写道,该聚合将展开集合中的数组,然后检查每个展开的文档是否与给定对象ID的数组中的任何元素匹配。投影时,所得的集合会经过条件进一步过滤。

  db.collectionName.aggregate([
    { $unwind: { 
          path: "$field5", 
          preserveNullAndEmptyArrays: true 
        } 
    },
    { $match: {  field5: { $in: 

       [
          ObjectId("id1"),
          ObjectId("id2"),
          ObjectId("id3")
      ]

        } } },
    { $project: { 
        _id: 0,
        field0: "$field0",
        field1: "$field1",
        field2: "$field2",
        customField: { 
            $or:[{
                  $and: [ 
                      { /*...some  condition*/ } ,  
                      { /*...some condition*/  }   
                    ],
                },
                { 
                    $and: [ 
                      { /*...some  condition*/ } , 
                      {  /*...some  condition*/ }   
                    ]
              }]
           }
       } 
     }
  ])     

这按预期工作。

结果

/* 1 */
{
    "field0" : "processing",
    "field5" : ObjectId("id1"),
    "field1" : "val",
    "field2" : "val",
    "customField" : false
}

/* 2 */
{
    "field0" : "processing",
    "field5" : ObjectId("id2"),
    "field1" : "val",
    "field2" : "val",
    "customField" : false
}

如果我理解正确,$ match阶段将删除不匹配的id(例如id3)。通过创建一个单独的文档并为其计划所有字段,我如何仍能在最终输出中得到它?

期望什么

/* 1 */
{
    "field0" : "processing",
    "field5" : ObjectId("id1"),
    "field1" : "val",
    "field2" : "val",
    "customField" : false
}

/* 2 */
{
    "field0" : "processing",
    "field5" : ObjectId("id2"),
    "field1" : "val",
    "field2" : "val",
    "customField" : true
}


/* 3 */
/* Note that id3 is unmatched (excluded by $match in result) */
{
    "field0" : "processing",
    "field5" : ObjectId("id3"),
    "field1" : "val",
    "field2" : "val",
    "customField" : true
}

有没有办法做到这一点?

1 个答案:

答案 0 :(得分:0)

是的,您可以实现,但这有点棘手。

$facet将有助于实现这一目标。

db.collection.aggregate([
  {
  $facet:{
    "matched":[
      { 
        $unwind:{ 
          path: "$field5", 
          preserveNullAndEmptyArrays: true 
        } 
      },
      { 
        $match:{  
          field5: {
            $in:
             [
                ObjectId("id1"),
                ObjectId("id2"),
                ObjectId("id3")
             ]
          } 
        } 
      },
      { 
        $project: { 
          _id: 0,
          field0: "$field0",
          field1: "$field1",
          field2: "$field2",
          customField: { 
              $or:[{
                    $and: [ 
                        { /*...some  condition*/ } ,  
                        { /*...some condition*/  }   
                      ],
                  },
                  { 
                      $and: [ 
                        { /*...some  condition*/ } , 
                        {  /*...some  condition*/ }   
                      ]
                }]
             }
         } 
       }
    ],
    "unmatched":[
    { 
      $unwind:{ 
        path: "$field5", 
        preserveNullAndEmptyArrays: true 
      } 
    },
    { 
      $match:{  
        field5: {
          $nin:
           [
              ObjectId("id1"),
              ObjectId("id2"),
              ObjectId("id3")
           ]
        } 
      } 
    },
    { 
      $project: { 
        _id: 0,
        field0: "$field0",
        field1: "$field1",
        field2: "$field2",
        customField: { 
            $or:[{
                  $and: [ 
                      { /*...some  condition*/ } ,  
                      { /*...some condition*/  }   
                    ],
                },
                { 
                    $and: [ 
                      { /*...some  condition*/ } , 
                      {  /*...some  condition*/ }   
                    ]
              }]
           }
       } 
     }
    ]
  }
  },
  {
    $project:{
      "all":{
        $concatArrays:[
          "$matched",
          "$unmatched"
        ]
      }
    }
  },
  {
    $unwind:"$all"
  },
  {
    $replaceRoot:{
      newRoot:"$all"
    }
  }
]).pretty()

希望这将对您的用例有所帮助。

此外,您可以根据需要更新两个方面(“匹配”和“不匹配”)。

您可以找到有关$ facet here

的更多信息