MongoDB: использовать массив, возвращенный из конвейера агрегации для $ в запросе на следующем этапе - PullRequest
0 голосов
/ 28 сентября 2018

Как видно из заголовка вопроса, я пытаюсь использовать поле массива, возвращенное со стадии $ match, чтобы запросить другую коллекцию на следующем этапе, используя $ lookup и оператор $ in, чтобы получить все документы, имеющие хотя бы одну категориювнутри этого массива.(Между прочим, я использую Mongoose в Node)

Я хочу сопоставить коллекцию "конфигураций" по '_id' с этой упрощенной схемой:

{
    title: {type: String, required: true},
    categories: {
        allow: {type: Boolean, required: true},
        list: [
            {
               name: {type: String, required: true},// DENORMALIZED CATEGORY NAME
               _id: {type: mongoose.Schema.Types.ObjectId}
            }
        ]
    }
}

И вНа следующем этапе я хочу объединить всех «партнеров», которые принадлежат как минимум одному из этих категорий.«партнеры» имеют следующую схему:

{
    company: {type: String, required: true},
    categories: [
        {type: mongoose.Schema.Types.ObjectId}
    ]
}

Вот что я сейчас делаю:

configuration.aggregate([
{$match: {_id: ObjectID(configurationId)}},
{
  $lookup: {
    from: "partners",
    pipeline: [
      {
        $match: {
          active: true,// MATCH ALL ACTIVE PARTNERS
          categories: {
            $in: {// HERE IS THE PROBLEM: I CAN'T RETRIEVE AN ARRAY FROM $map OPERATOR
              $map: {// MAP CONFIGURATION CATEGORY LIST TO OUTPUT AN ARRAY ONLY WITH ID OBJECTS
                input: '$categories.list',
                as: 'category',
                in: '$$category._id'
              }
            }
          }
        }
      },
      { $project: { _id: 1, company: 1 } }
    ],
    as: "partners"
  }
},
])

Оператор $ map работает, как и ожидалось, на этапе $ project, нов этом случае я просто не могу использовать его результат как массив для использования с оператором $ in.

Есть ли способ сделать это?

Спасибо!

ОБНОВЛЕНИЕ

Работа, подобная предложенной @Veeram, устраняет необходимость использования оператора $ map на этапе поиска $:

{
  "$lookup":{
    "from":"partners",
    "let":{"categories_id":"$categories.list._id"},
    "pipeline":[
      {"$match":{"active":true,"$expr":{"$in":["$categories","$$categories_id"]}}},
      {"$project":{"_id":1,"company":1}}
    ],
    "as":"partners"
  }
}

Но проблема сохраняется с оператором $ in.Как я уже говорил, этот вариант использования $ такой же, как и в 4-м примере официальной документации (docs.mongodb.com/manual/reference/operator/aggregation/in), и в результате получается ложное утверждение, потому что мыпытаемся проверить, является ли массив ("$ Categories") элементом другого массива ("$$ Categories_id"), что приведет к сбою, поскольку элементы "$$ Categories_id" являются объектами id, а не массивами.

Кто-нибудь знает, есть ли обходной путь для этого?

Спасибо!

1 Ответ

0 голосов
/ 28 сентября 2018

Вам не нужно использовать $ map.Вы можете использовать точечную запись для доступа к идентификаторам.

$let требуется для доступа к значениям из локальной коллекции и $expr для сравнения полей документа.

Что-то вроде

  {
  "$lookup":{
    "from":"partners",
    "let":{"categories_id":"$categories.list._id"},
    "pipeline":[
      {"$match":{
        "active":true,
        "$expr":{
          "$gt":[
            {"$size":{"$setIntersection":["$categories","$$categories_id"]}},
            0
          ]
        }
      }},
      {"$project":{"_id":1,"company":1}}
    ],
    "as":"partners"
  }
}
...