В чем заключается проблема адресации моего сложного документа 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 документов:

Когда я попытался обновить "воздушный" ключ документа "Сан-Франциско", я получил неожиданный результат. Вместо того, чтобы обновить "воздух": "сухой" он создал новый ключ "воздух" в объекте "Сан-Франциско":

Так что я подумал, давайте попробуем обновить снова и посмотрим, что произойдет:

Как вы можете видеть, он обновил ранее созданный "воздушный" ключ. Я мог бы бороться с этим и попытаться заставить его работать "по-моему", но я просто хочу, чтобы это работало, поэтому я снова перенастраиваю макет своей коллекции в соответствии с тем, что "работает":

И снова запустите обновление:

Затем я проверяю это, запустив обновление снова:

Это работает, я корректно обновляюсь в многодокументной среде. Итак, это мой текущий рабочий макет коллекции:

У меня есть пара вопросов об этом

  1. Я использую ключ верхнего уровня "погода" в каждом документе. Это ничего не добавляет к информации в документе. Есть ли изменение дизайна макета, которое не потребует того ключа и накладных расходов, которые он несет?

  2. Допустим, я должен использовать клавишу "Погода". Его значение является массивом, но этот массив имеет только один элемент, объект, который содержит ключи: город, небо, воздух и земля. Обязательна ли адресация для использования массива только с одним элементом? Или я мог бы избавиться от этого. Вместо "погода":[{}] может ли дизайн быть "погода":{} или я снова столкнусь с проблемами неадресуемости?

  3. Похоже, что теперь я могу обновить () любое из значений для ключей: воздух, небо и земля, но какова структура find(), чтобы сказать ЧИТАТЬ значение ключа "земля" в одном из документов?

----> Хорошо, я думаю, что у меня есть этот вопрос #3- db.weatherSys.find({ "weather.city": "San Francisco" }, { "weather.ground": 1 })

  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})

В исходном макете коллекции, который вы предложили, не могли бы вы объяснить мне, почему он не обновлялся так, как вы и я ожидали, а вместо этого создал новый объект "город"?

Это ошибка копирования-вставки. Я хотел предложить вам рабочий макет прямо сейчас. Обновил мой предыдущий макет.

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