В чем заключается проблема адресации моего сложного документа update() в MongoDB?
Мне не удалось войти в мою коллекцию MongoDB и изменить значение в сложном документе. Я перепробовал больше вариантов, чем в приведенном ниже примере, все виды вариантов, но они терпят неудачу.
Я хочу изменить значение ключа "воздух" с "дождь" на "очистить". В реальной жизни я не буду знать, что текущее значение ключа "воздух" - это "дождь".
Обратите внимание, я не использую объект MongoDB _id и хотел бы сделать это без его использования.
3 документа в коллекции weatherSys:
{
"_id" : ObjectId("58a638fb1831c61917f921c5"),
"SanFrancisco" : [
{ "sky" : "grey" },
{ "air" : "rain" },
{ "ground" : "wet" }
]
}
{
"_id" : ObjectId("58a638fb1831c61917f921c6"),
"LosAngeles" : [
{ "sky" : "grey" },
{ "air" : "rain" },
{ "ground" : "wet" }
]
}
{
"_id" : ObjectId("58a638fb1831c61917f921c7"),
"SanDiego" : [
{ "sky" : "grey" },
{ "air" : "rain" },
{ "ground" : "wet" }
]
}
var docKey = "LosAngeles";
var subKey = "air";
var newValue = "clear";
var query = {};
//var queryKey = docKey + ".$";
query[query] = subKey; // query = { }
var set = {};
var setKey = docKey + ".0." + subKey;
set[setKey] = newValue; // set = { "weather.0.air" : "clear" }
db.collection('weatherSys').update(query, { $set: set }, function(err, result) {
if (err) throw err;
});
ОБНОВЛЕНИЕ-1: Хорошо, я надеялся, что смогу найти макет немного проще, чем вы предлагали, но я потерпел неудачу. Все, что я пробовал, не было адресуемым на уровне "воздуха". Поэтому я скопировал и вставил ваш точный JSON в свою коллекцию и запустил его. Я использую MongoChef для манипулирования и тестирования коллекции.
Вот мой новый макет, который использовался для вставки JSON в 3 раза для создания 3 документов:
Когда я попытался обновить "воздушный" ключ документа "Сан-Франциско", я получил неожиданный результат. Вместо того, чтобы обновить "воздух": "сухой" он создал новый ключ "воздух" в объекте "Сан-Франциско":
Так что я подумал, давайте попробуем обновить снова и посмотрим, что произойдет:
Как вы можете видеть, он обновил ранее созданный "воздушный" ключ. Я мог бы бороться с этим и попытаться заставить его работать "по-моему", но я просто хочу, чтобы это работало, поэтому я снова перенастраиваю макет своей коллекции в соответствии с тем, что "работает":
И снова запустите обновление:
Затем я проверяю это, запустив обновление снова:
Это работает, я корректно обновляюсь в многодокументной среде. Итак, это мой текущий рабочий макет коллекции:
У меня есть пара вопросов об этом
Я использую ключ верхнего уровня "погода" в каждом документе. Это ничего не добавляет к информации в документе. Есть ли изменение дизайна макета, которое не потребует того ключа и накладных расходов, которые он несет?
Допустим, я должен использовать клавишу "Погода". Его значение является массивом, но этот массив имеет только один элемент, объект, который содержит ключи: город, небо, воздух и земля. Обязательна ли адресация для использования массива только с одним элементом? Или я мог бы избавиться от этого. Вместо "погода":[{}] может ли дизайн быть "погода":{} или я снова столкнусь с проблемами неадресуемости?
Похоже, что теперь я могу обновить () любое из значений для ключей: воздух, небо и земля, но какова структура find(), чтобы сказать ЧИТАТЬ значение ключа "земля" в одном из документов?
----> Хорошо, я думаю, что у меня есть этот вопрос #3- db.weatherSys.find({ "weather.city": "San Francisco" }, { "weather.ground": 1 })
- В исходном макете коллекции, который вы предложили, не могли бы вы объяснить мне, почему он не обновился так, как вы и я ожидали, а вместо этого создал новый объект "город"?
Здесь много Я ценю вашу приверженность этому.
1 ответ
Вы не можете использовать позиционный оператор для запроса массива по его ключу.
Вы можете получить доступ к weather
массив по индексу, но это означает, что вы знаете индекс массива.
Например, если вы хотите обновить air
значение элемента в weather
массив.
db.collection('weatherSys').update( {}, { $set: { "weather.1.air" : "clear"} } );
Обновить:
К сожалению, я не вижу способа обновить значения, не зная индекс массива для ключа.
Вам не нужен объект запроса, так как ваши ключи уникальны.
db.collection('weatherSys').update( {}, { $set: { "SanFrancisco.1.air" : "clear"} } );
или же
Другой вариант, если вы хотите убедиться, что ключ существует.
db.collection('weatherSys').update( { "SanFrancisco": { $exists: true } }, { $set: { "SanFrancisco.1.air" : "clear"} } );
Не уверен, что сможете, но сможете ли вы обновить свою структуру до уровня ниже.
{
"_id" : ObjectId("58a638fb1831c61917f921c5"),
"weather" : [
{
"city": "LosAngeles",
"sky" : "grey" ,
"air" : "rain" ,
"ground" : "wet"
}
]
}
Теперь вы можете использовать $positional
Оператор для обновления.
db.collection('weatherSys').update( {"weather.city":"LosAngeles"}, { $set: { "weather.$.air" : "clear"} } );
Я использую ключ верхнего уровня "погода" в каждом документе. Это ничего не добавляет к информации в документе. Есть ли изменение дизайна макета, которое не потребует того ключа и накладных расходов, которые он несет?
Единственный макет, о котором я могу думать, это продвижение всех встроенных свойств на верхний уровень. Извините, не уверен, почему я не подумал об этом в первый раз. Иногда вам нужен правильный вопрос, чтобы получить правильный ответ.
{
"_id" : ObjectId("58a638fb1831c61917f921c5"),
"city": "LosAngeles",
"sky" : "grey",
"air" : "rain",
"ground" : "wet"
}
Все обновления будут просто обновлениями верхнего уровня.
db.collection('weatherSys').update( {"city":"LosAngeles"}, { $set: { "air" : "clear"} } );
Допустим, я должен использовать клавишу "Погода". Его значение является массивом, но этот массив имеет только один элемент, объект, который содержит ключи: город, небо, воздух и земля. Обязательна ли адресация для использования массива только с одним элементом? Или я мог бы избавиться от этого. Вместо "погода":[{}] может ли дизайн быть "погода":{} или я снова столкнусь с проблемами неадресуемости?
N / A, если вы в порядке с первым предложением.
Похоже, что теперь я могу обновить () любое из значений для ключей: воздух, небо и земля, но какова структура find(), чтобы сказать ЧИТАТЬ значение ключа "земля" в одном из документов?
db.weatherSys.find ({"city": "San Francisco"}, {"ground": 1})
В исходном макете коллекции, который вы предложили, не могли бы вы объяснить мне, почему он не обновлялся так, как вы и я ожидали, а вместо этого создал новый объект "город"?
Это ошибка копирования-вставки. Я хотел предложить вам рабочий макет прямо сейчас. Обновил мой предыдущий макет.