#javascript #mongodb
Вопрос:
У меня есть схема, в которой свойства могут иметь соответствующие «переопределяющие» документы, хранящиеся в массиве(«переопределяет»)
Напр.
{
foo:'original foo',
overrides: [
{property:'foo', value:'foo override'},
{property:'bar', value:'bar override'},
]
}
Я хочу спроецировать поле для переопределенного значения, если оно существует, в противном случае исходное свойство.
Так что что-то вроде этого
project: { overrideOrOriginal: {$cond: fooOverrideExists ? fooOverrideValue : originalFooValue }
Так что в этом примере я ожидал overrideOrOriginal
бы равенства 'foo override'
. Если — {property:'foo', value:'foo override'}
subDoc не существовал в overrides
массиве (или если overrides
сам массив даже не существовал)…тогда я ожидал бы переопределения оригинала = ‘оригинальный фу’
Как я могу это сделать? Я подумал, что мне понадобится $exists
в тандеме с $cond
. Но сложность здесь в том, что я ищу подДок в массиве на основе запроса
Спасибо!
Комментарии:
1. если вы дадите ожидаемый результат, это очень поможет
2. если вы можете объяснить нам, во всех ваших документах есть это поле «foo»? или у каждого документа может быть другое название для «foo»? и вы хотите сделать это во всех документах или для определенного значения «foo»? Добавьте 2-3 документа и опубликуйте ожидаемый результат, иначе мы отправим ответы, предполагающие разные вещи
Ответ №1:
$ifNull
чтобы проверить, является ли поле пустым, затем верните пустой массив$in
чтобы проверить, находится ли «foo» вoverrides.property
массиве$indexOfArray
чтобы получить индекс элемента массива вoverrides.property
массиве$arrayElemAt
чтобы получить элемент по определенному индексу, возвращаемый оператором выше
let fooOverrideExists = "foo";
db.collection.find({},
{
overrideOrOriginal: {
$cond: [
{
$in: [
fooOverrideExists,
{ $ifNull: ["$overrides.property", []] }
]
},
{
$arrayElemAt: [
"$overrides.value",
{ $indexOfArray: ["$overrides.property", fooOverrideExists] }
]
},
"$foo"
]
}
})
Комментарии:
1. Это должно сработать, но мне нужно учитывать, если
$overrides.property
этого не существует. Я пробовал использовать$and
в сочетании с вашим$in
, но продолжаю получать синтаксические ошибки. Похоже , мне нужно использовать составное выражение внутри$cond
, но это тоже не удается. Есть какие-нибудь идеи?2. Я не совсем вас понимаю, можете ли вы опубликовать пример этого случая в своем вопросе.
3. Пожалуйста, прокомментируйте
$overrides
это на своей игровой площадке, и вы увидите$in requires an array as a second argument, found: missing
ошибку. Учет того, существует ли этот массив, должен это исправить. Итак, если его не существует, я бы хотел$cond
потерпеть неудачу и просто вернуть «$foo».4. Я обновил ответ.
5. это работает для определенного «foo», и только в том случае, если все документы во всей коллекции содержат только «foo» в качестве полей, проверьте, что этот вопрос нуждается в более четком объяснении, я думаю
Ответ №2:
Запрос
- найдите свойство , значение ключа(kv) (оно работает для всех имен свойств)
(предполагается, что ваша схема содержит только строковое значение, значение этого свойства). - проверяет, существует ли он в массиве переопределений
- если он существует, принимает значение из массива
- остальное сохраняет оригинал
*проверяет также случаи, когда переопределение не существует, или его пустой массив, или свойство не существует
*в случае, если вы хотите сделать это только для определенного «foo», сначала проигнорируйте big $set
и используйте этот код
db.collection.aggregate([
{
"$set": {
"kv": {
"$arrayElemAt": [
{
"$filter": {
"input": {
"$objectToArray": "$ROOT"
},
"cond": {
"$eq": [
{
"$type": "$this.v"
},
"string"
]
}
}
},
0
]
}
}
},
{
"$set": {
"index": {
"$indexOfArray": [
"$overrides.property",
"$kv.k"
]
}
}
},
{
"$project": {
"_id": 0,
"overrideOrOriginal": {
"$cond": [
{
"$or": [
{
"$eq": [
"$index",
-1
]
},
{
"$not": [
"$overrides"
]
}
]
},
"$kv.v",
{
"$arrayElemAt": [
"$overrides.value",
"$index"
]
}
]
}
}
}
])