Допустим, у меня есть этот документ
[
{
"_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, не извлекайте этот документ.
Как правило, я не рекомендую схему с массивами с высокой степенью вложенности. Тем не менее, в вашем сценарии вы можете сначала выполнить поэлементную операцию над 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 Это несколько умных хаков! Спасибо, что научили меня этому :)
@aneroid спасибо за ответы. Проблема в том, что я только что увидел структуру базы данных, и случилось так, что negedArray.value — это строка, а negedArray2.valueToFilter — это ObjectId, что приводит к сбою пересечения. есть ли способ это исправить? я пробовал использовать $toObjectId/$toString, но, видимо, это запрещено внутри $setIntersection
@matthew, можешь отредактировать вопрос, включив в него образец документа?
@ray обновлен по запросу
@aneroid извините за путаницу, я исправил ObjectId, спасибо за предложения.
@matthew обновил ответ, чтобы приспособиться к изменениям. По сути, я дезинфицирую поле с помощью $toObjectId
перед конвейером. Однако вы можете видеть, что код усложняется из-за большого количества $mergeObjects
из-за высокой вложенности структуры. О преимуществах рефакторинга записей array
в отдельные документы вам напоминают в предыдущих комментариях.
Хорошо, а что ты уже пробовал? Добро пожаловать в StackOverflow. Покажите, что вы уже пробовали (код), и уточните, какая часть вызывает у вас проблемы. Читайте: Как создать минимальный воспроизводимый пример . Пожалуйста, пройдите тур и прочитайте Как мне задать хороший вопрос?.