$ поиск с конвейером медленнее, чем ожидалось

#mongodb #mongodb-query #aggregation-framework

#mongodb #mongodb-запрос #агрегация-фреймворк

Вопрос:

У меня есть следующий $lookup этап агрегации:

     {
        $lookup: {
            from: "target",
            let: {byTargetId: "$foreignTargetId"},
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $eq: ["$targetId", "$byTargetId"]
                        }
                    }
                },
                {
                    $project: {
                        someTargetProperty: true
                    }
                }
            ],
            as: "targets"
        }
    }
 

В моей тестовой базе данных этап перед этим возвращает только 5 документов. В этом случае ни один из них не имеет необязательного свойства foreignTargetId , поэтому я ожидаю byTargetId , что будет undefined каждый раз, и ни один документ в target коллекции не будет совпадать.

Дело в том, что агрегация занимает на 1 секунду больше времени, если я добавлю этот этап поиска (в конце).

Если я выполню эту агрегацию для target коллекции, которая идентична конвейеру поиска со undefined значением для byTargetId :

 db.getCollection('target').aggregate(
[
    {
        $match: {
            $expr: {
                $eq: ["$targetId", undefined]
            }
        }
    },
    {
        $project: {
            someTargetProperty: true
        }
    }
])
 

тогда действительно это занимает около 200 мс, а 5×200 мс = 1 с, так что это имеет смысл.

Тем не менее, если я выполню ту же агрегацию со null значением для byTargetId :

 db.getCollection('target').aggregate(
[
    {
        $match: {
            $expr: {
                $eq: ["$targetId", null]
            }
        }
    },
    {
        $project: {
            someTargetProperty: true
        }
    }
])
 

затем это выполняется за <1 мс.

  1. Чем вызвана такая большая разница между равенством совпадений на null и undefined ?
  2. Как я могу пропустить этап $lookup, если foreignTargetId он отсутствует во входном документе для этого этапа?

Кстати, причина, по которой я использую конвейер поиска здесь, заключается в том, что документы в target нем довольно большие, и мне нужно только someTargetProperty то, что также находится в индексе, поэтому поиск может быть выполнен полностью в памяти. В других случаях я заметил, что это может быть значительно быстрее, чем просмотр всего документа и последующее проектирование. Я не буду принимать ответы, которые пытаются обойти эту проблему, не используя $lookup с конвейером.