Как включить несоответствующие документы в вывод агрегации mongodb? - PullRequest
1 голос
/ 01 марта 2020

Я написал ниже агрегацию, которая раскручивает массив в коллекции и затем проверяет, соответствует ли каждый размотанный документ какому-либо элементу в данном массиве идентификаторов объектов. При проецировании результирующая коллекция проходит через условие для дальнейшей фильтрации.

  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 stage удаляет непревзойденный идентификатор (скажем, 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 голосов
/ 02 марта 2020

Да, вы можете достичь этого, но это немного сложно.

$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 здесь

...