Фильтрация массива на основе свойства другого массива в агрегации mongodb

Допустим, у меня есть этот документ

[
  {
    "_id": 1,
    "array": [
      {
        "name": "name1",
        "nestedArray": [
          {
            "value": "661564ce168c8115295a8f25"
          }
        ],
        "nestedArray2": [
          {
            "valueToFilter": ObjectId("661564ce168c8115295a8f25")
          }
        ]
      },
      {
        "name": "name2",
        "nestedArray": [
          {
            "value": "661564ce168c8115295a8f27"
          },
                    {
            "value": "661564ce168c8115295a8f28"
          }
        ],
        "nestedArray2": [
          {
            "valueToFilter": ObjectId("661564ce168c8115295a8f29")
          }
        ]
      }
    ]
  }
]

Мне нужно получить _id и свойства целого массива, если ПО МИНИМУМ один элемент внутриnestedArray2.valueToFilter не существует внутриnestedArray.value

Таким образом, в этом примере агрегирование вернет этот документ, поскольку вложенныйArray2.valueToFilter: v3 не существует хотя бы в одном вложенном массиве.value.

Если все значения valueToFilter существуют хотя бы в одном вложенном массиве.value, не извлекайте этот документ.

Хорошо, а что ты уже пробовал? Добро пожаловать в StackOverflow. Покажите, что вы уже пробовали (код), и уточните, какая часть вызывает у вас проблемы. Читайте: Как создать минимальный воспроизводимый пример . Пожалуйста, пройдите тур и прочитайте Как мне задать хороший вопрос?.

aneroid 05.04.2024 22:41
Использование JavaScript и MongoDB
Использование JavaScript и MongoDB
Сегодня я собираюсь вкратце рассказать о прототипах в JavaScript, а также представить и объяснить вам работу с базой данных MongoDB.
0
1
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Как правило, я не рекомендую схему с массивами с высокой степенью вложенности. Тем не менее, в вашем сценарии вы можете сначала выполнить поэлементную операцию над array, чтобы вычислить $setIntersection из nestedArray и $nestedArray2. Затем используйте $anyElementTrue, чтобы отфильтровать результат.

db.collection.aggregate([
  {
    "$set": {
      "array": {
        "$map": {
          "input": "$array",
          "as": "a",
          "in": {
            "$mergeObjects": [
              "$$a",
              {
                nestedArray: {
                  "$map": {
                    "input": "$$a.nestedArray",
                    "as": "na",
                    "in": {
                      "value": {
                        "$toObjectId": "$$na.value"
                      }
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  {
    "$set": {
      "test": {
        "$map": {
          "input": "$array",
          "as": "arr",
          "in": {
            "$setIntersection": [
              "$$arr.nestedArray.value",
              "$$arr.nestedArray2.valueToFilter"
            ]
          }
        }
      }
    }
  },
  {
    "$match": {
      $expr: {
        "$anyElementTrue": {
          "$map": {
            "input": "$test",
            "as": "t",
            "in": {
              $eq: [
                [],
                "$$t"
              ]
            }
          }
        }
      }
    }
  },
  {
    $unset: "test"
  }
])

Игровая площадка Монго


Вышеупомянутая игровая площадка демонстрирует концепции. Вы можете использовать приведенную ниже версию для краткого синтаксиса. Игровая площадка Монго

Один ярлык, который мне нравится использовать для нескольких проверок на равенство пустых и непустых значений, — это max/min. В этом случае упрощаем $match до: { $expr: { $eq: [{ $min: "$test" }, []] } }Игровая площадка Mongo с лучшими данными

aneroid 05.04.2024 23:36

@aneroid Это несколько умных хаков! Спасибо, что научили меня этому :)

ray 05.04.2024 23:42

@aneroid спасибо за ответы. Проблема в том, что я только что увидел структуру базы данных, и случилось так, что negedArray.value — это строка, а negedArray2.valueToFilter — это ObjectId, что приводит к сбою пересечения. есть ли способ это исправить? я пробовал использовать $toObjectId/$toString, но, видимо, это запрещено внутри $setIntersection

matthew 09.04.2024 18:07

@matthew, можешь отредактировать вопрос, включив в него образец документа?

ray 09.04.2024 18:56

@ray обновлен по запросу

matthew 09.04.2024 19:10

@aneroid извините за путаницу, я исправил ObjectId, спасибо за предложения.

matthew 09.04.2024 19:36

@matthew обновил ответ, чтобы приспособиться к изменениям. По сути, я дезинфицирую поле с помощью $toObjectId перед конвейером. Однако вы можете видеть, что код усложняется из-за большого количества $mergeObjects из-за высокой вложенности структуры. О преимуществах рефакторинга записей array в отдельные документы вам напоминают в предыдущих комментариях.

ray 09.04.2024 20:58

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