Использовать значения массива в качестве ключа в $match stage mongodb

Учитывая перечень документов, таких как:

[
  {
    _id: 1,
    field1: "test",
    field2: "value2",
    fields: [
      "field1",
      "field2"
    ]
  },
  {
    _id: 2,
    field1: "value1",
    field2: "test",
    fields: [
      "field1",
      "field2"
    ]
  },
  {
    _id: 3,
    field1: "test",
    field2: "value2",
    fields: [
      "field2"
    ]
  },
  {
    _id: 4,
    field1: "value1",
    field2: "value2",
    fields: [
      "field1"
    ]
  },
  {
    _id: 5,
    field1: "test",
    field2: "test",
    fields: []
  }
]

Я хочу получить все документы, которые имеют любое из указанных полей в массиве со значением «тест». Например, в документе с _id: 1field2 является значением массива fields, а field2 имеет test в качестве значения. Напротив, документ с _id: 5 имеет ключи field1 и field2 с проверочным значением, но ни одно из этих полей не присутствует в массиве полей. Итак, учитывая предыдущий список документов, возвращать следует только документы с _id: 1 и _id: 2.

что-то вроде этого, может быть mongoplayground.net/p/wVOsyL2oQrH или mongoplayground.net/p/0WGF4W4cjXA

cmgchess 14.08.2024 16:29

еще лучше с $in mongoplayground.net/p/-4hn4gibp-0 в первом $addField

cmgchess 14.08.2024 16:45
Использование JavaScript и MongoDB
Использование JavaScript и MongoDB
Сегодня я собираюсь вкратце рассказать о прототипах в JavaScript, а также представить и объяснить вам работу с базой данных MongoDB.
1
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

возможный подход в виде шагов

  1. Создайте временное поле массива пар ключ-значение из field1,field2.., чтобы его можно было фильтровать/искать.
  2. Выполните сравнение, используя совпадение.
  3. Удалите временное поле, добавленное на первом этапе.

Подход с $anyElementTrue на стадии матча - демо

db.collection.aggregate([
  {
    $addFields: {
      keyValuePairArray: {
        $filter: {
          input: { $objectToArray: "$$ROOT" },
          cond: { $not: { $in: [ "$$this.k", ["_id", "fields"] ] } }
        }
      }
    }
  },
  {
    $match: {
      $expr: {
        $anyElementTrue: {
          $map: {
            input: "$keyValuePairArray",
            in: {
              $and: [
                { $in: [ "$$this.k", "$fields" ] },
                { $eq: [ "$$this.v", "test" ] }
              ]
            }
          }
        }
      }
    }
  },
  { $unset: "keyValuePairArray" }
])

Другой подход с $filter на этапе матча, проверив его размер - демо

db.collection.aggregate([
  {
    $addFields: {
      keyValuePairArray: {
        $filter: {
          input: { $objectToArray: "$$ROOT" },
          cond: { $not: { $in: [ "$$this.k", ["_id", "fields"] ] } }
        }
      }
    }
  },
  {
    $match: {
      $expr: {
        $gt: [
          {
            $size: {
              $filter: {
                input: "$keyValuePairArray",
                cond: {
                  $and: [
                    { $in: [ "$$this.k", "$fields" ] },
                    { $eq: [ "$$this.v", "test" ] }
                  ]
                }
              }
            }
          },
          0
        ]
      }
    }
  },
  { $unset: "keyValuePairArray" }
])

РЕДАКТИРОВАНИЕ - вам может даже не понадобиться временное поле, удалив _id и fields, поскольку они все равно не повлияют на сравнение $match - проверьте демо

db.collection.aggregate([
  {
    $match: {
      $expr: {
        $anyElementTrue: {
          $map: {
            input: { $objectToArray: "$$ROOT" },
            in: {
              $and: [
                { $in: [ "$$this.k", "$fields" ] },
                { $eq: [ "$$this.v", "test" ] }
              ]
            }
          }
        }
      }
    }
  }
])

Я принимаю ответ, потому что он решает именно то, что я спросил. Но мой вопрос был неверным и данные тоже. Я перефразировал вопрос здесь, что немного сложнее.

biorubenfs 16.08.2024 10:15

Другие вопросы по теме