2011-12-14 5 views
3

У меня есть следующие коллекции:Multiple обновление свойств встроенных документов

{ 
"Milestones" : [  
    {  "ActualDate" : null, 
    "Index": 0, 
    "Name" : "milestone1", 
    "TargetDate" : ISODate("2011-12-13T22:00:00Z"),   
    "_id" : ObjectId("4ee89ae7e60fc615c42e28d1")},   
    {  "ActualDate" : null,  
    "Index" : 0,  
    "Name" : "milestone2", 
    "TargetDate" : ISODate("2011-12-13T22:00:00Z"),   
    "_id" : ObjectId("4ee89ae7e60fc615c42e28d2") } ] 
, 
"Name" : "a", "_id" : ObjectId("4ee89ae7e60fc615c42e28ce") 
} 

Я хочу, чтобы обновить определенные документы: которые указанные _id, Список Milestones._id и ActualDate является нулевым. Я Dotnet мой код выглядит следующим образом:

var query = Query.And(new[] { Query.EQ("_id", ObjectId.Parse(projectId)), 
    Query.In("Milestones._id", new BsonArray(values.Select(ObjectId.Parse))), 
Query.EQ("Milestones.ActualDate", BsonNull.Value) });     

var update = Update.Set("Milestones.$.ActualDate", DateTime.Now.Date);  

Coll.Update(query, update, UpdateFlags.Multi, SafeMode.True); 

Или в нативном коде:

db.Projects.update({ "_id" : ObjectId("4ee89ae7e60fc615c42e28ce"), "Milestones._id" : { "$in" : [ObjectId("4ee89ae7e60fc615c42e28d1"), ObjectId("4ee89ae7e60fc615c42e28d2"), ObjectId("4ee8a648e60fc615c41d481e")] }, "Milestones.ActualDate" : null },{ "$set" : { "Milestones.$.ActualDate" : ISODate("2011-12-13T22:00:00Z") } }, false, true) 

Но только первый элемент обновляется.

ответ

10

В настоящий момент это невозможно. Флаг multi в обновлении означает обновление нескольких корневых документов. Оператор positional может соответствовать только одному вложенному элементу массива. В mongodb jira есть такой feature. Вы можете проголосовать и подождать.

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

Из документации на mongodb.org:

В настоящее время $ оператор применяется только к совпавшего элемента в запросе

+0

Thx, Эндрю. Я поднял вопрос в джире. Надеюсь, они это осуществят. – 1gn1ter

+2

@ 1gn1ter: эта функция была одобрена, но не запланирована :( –

+2

4 года спустя, поддерживается ли она? –

1

Как ответил Эндрю Orsich, это не возможно, на данный момент, по крайней мере, не так, как вы пожелаете. Но загрузка документа, изменение массива, а затем сохранение его обратно будет работать. Риск состоит в том, что какой-то другой процесс может изменить массив в то же время, поэтому вы должны перезаписать его изменения. Чтобы этого избежать, вы можете использовать оптимистичную блокировку, особенно если массив не изменяется каждую секунду.

  1. нагрузки документ, в том числе новый атрибут: milestones_version
  2. изменять массив при необходимости
  3. сохранить обратно в MongoDB, но теперь добавить ограничение запросов на milestones_version, и увеличить его:

    db.Projects.findAndModify({ 
        query: { 
         _id: your_project_id, 
         milestones_version: expected_milestones_version 
        }, 
        update: { 
         $set: { 
          Milestones: modified_milestones 
         }, 
         $inc: { 
          milestones_version: 1 
         } 
        }, 
        new: 1 
    }) 
    

Если другой процесс изменил массив вех (и, следовательно, milestones_version), прежде чем мы это сделали, тогда эта команда ничего не делает и просто возвращает null. Нам просто нужно перезагрузить документ и повторить попытку. Если массив не изменяется каждую секунду, то это будет очень редко и не будет иметь никакого влияния на производительность.

Основная проблема с этим решением заключается в том, что вы должны редактировать каждый проект, один за другим (нет multi: true). Вы все равно можете написать функцию javascript и запустить ее на сервере.

0

По своей странице JIRA «Эта новая функция доступна начиная с версии развития MongoDB 3.5.12, а также включены в MongoDB 3,6 серийной версии»

https://jira.mongodb.org/browse/SERVER-1243

Смежные вопросы