Как обновить встроенный документ монго, используя API данных Spring Mongo

1
    I need some help updating property of embedded collection with JSON structure below       -
     translation
    {
     "_id" : ObjectId("533d4c73d86b8977fda970a9"),
     "_class" : "com.xxx.xxx.translation.domain.Translation",
     "locales" : [ 
       {
        "_id" : "en-US",
        "description" : "English (United States)",
        "isActive" : true
       }, 
      {
        "_id" : "pt-BR",
        "description" : "Portuguese (Brazil)",
        "isActive" : true
      }, 
     {
        "_id" : "nl-NL",
        "description" : "Dutch (Netherlands)",
        "isActive" : true
     }
     ],
     "screens" : [ 
     {
        "_id" : "caseCodes",
        "dictionary" : [ 
            {
                "key" : "CS_CAT1",
                "parameterizedValue" : "My investigations",
                "locale" : "en-US"
            }, 
            {
                "key" : "MY_INVESTIGATIONS",
                "parameterizedValue" : "",
                "locale" : "pt-BR"
            }, 
       }
      ]
     }

В приведенной выше структуре: я хочу обновить "parameterizedValue" usinng spring-data-mongo-db API 1.3.4, для экрана с _id = "caseCodes" и key = "CS_CAT1".

Я попробовал (здесь "values" - это имя коллекции для массива TranslationValue)

      mongoOperations.updateFirst(Query.query(Criteria.where("screens._id")
            .is("caseCodes")), new Update().push(
            "screens.dictionary.$.values", translationValue),
            Translation.class);

но он сказал: "Невозможно добавить массив в строковый" словарь "....

Любые указатели или помощь здесь? Благодарю.

-Sanjeev

Теги:
spring
mongodb-query

1 ответ

3
Лучший ответ

Есть несколько проблем с вашей логикой, а также проблемы с вашей схемой для этого типа обновления.

Во-первых, у вас есть вложенные массивы, и это вызывает проблему с обновлениями, как описано в документации для оператора positional $. Это означает, что любое условие, соответствующее элементу массива на стороне запроса инструкции обновления, будет соответствовать только найденному первому найденному индексу.

Поскольку вам нужна определенная запись во внутреннем массиве, вам также нужно будет это сопоставить. Но "улов" говорит, что в оператор позиционирования будет использоваться только первое совпадение, так что вы не можете иметь оба. Форма запроса (если бы можно было работать, а это не так) на самом деле была бы чем-то вроде этого (native shell):

db.collection.update(
    { 
        "screens._id": "caseCodes",
        "screens.dictionary.key": "CS_CAT1"
    },
    {
        "$set": { 
            "screens.$.dictionary.$.parameterizedValue": "new value"
        }
    }
)

Теперь это будет "более корректным", чем то, что вы делаете, но, конечно, это не удается, потому что оператор позиционирования не может использоваться более одного раза. Я могу просто глупо работать в этом случае, так как бывает так, что первый сопоставленный индекс массива "экранов" (который равен 0), как оказалось, точно такой же, как и требуемый индекс внутреннего элемента. Но на самом деле это просто "глупая удача".

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

db.collection.update(
    { 
        "screens._id": "caseCodes",
        "screens.dictionary.key": "MY_INVESTIGATIONS"
    },
    {
        "$set": { 
            "screens.0.dictionary.1.parameterizedValue": "new value"
        }
    }
)

Также отмечая, что правильный оператор для использования здесь равен $set поскольку вы не добавляете ни один из массивов, а скорее хотите изменить элемент.

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

     "screens" : {
         "caseCodes": [ 
             {
                 "key" : "CS_CAT1",
                 "parameterizedValue" : "My investigations",
                 "locale" : "en-US"
             }, 
             {
                 "key" : "MY_INVESTIGATIONS",
                 "parameterizedValue" : "",
                 "locale" : "pt-BR"
             }, 
         ]
     }

Это изменило форму на:

db.collection.update(
    { 
        "screens.caseCodes.key": "CS_CAT1"
    },
    {
        "$set": { 
            "screens.caseCodes.$.parameterizedValue": "new value"
        }
    }
)

Это может работать или не работать в ваших целях, но вы либо живете с ограничениями использования вложенного массива, либо каким-либо образом меняете свою схему.

  • 0
    Спасибо, Нил. Это - "$ set": {"screen.0.dictionary.1.parameterizedValue ":" new value "}
  • 0
    это сработало для меня.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню