2012-03-13 3 views
7

У меня есть база данных документов человека. У каждого есть поле с именем photos, которое представляет собой массив фотодокументов. Я хотел бы добавить новый «проверенный» флаг в каждый из фотодокументов и инициализировать его ложным.Добавить новое поле во все документы во вложенном массиве

Это запрос, я пытаюсь использовать:

db.person.update({ "_id" : { $exists : true } }, {$set : {photos.reviewed : false} }, false, true) 

Однако я получаю следующее сообщение об ошибке:

SyntaxError: missing : after property id (shell):1 

Возможно ли это, и если да, то, что я делаю неправильно в моем Обновить?

Вот полный пример «персона» документа:

{ 
"_class" : "com.foo.Person", 
"_id" : "2894", 
"name" : "Pixel Spacebag", 
"photos" : [ 
    { 
     "_id" : null, 
     "thumbUrl" : "http://site.com/a_s.jpg", 
     "fullUrl" : "http://site.com/a.jpg" 
    }, 
    { 
     "_id" : null, 
     "thumbUrl" : "http://site.com/b_s.jpg", 
     "fullUrl" : "http://site.com/b.jpg" 
    }] 
} 

Bonus кармы для тех, кто может сказать мне уборщик почему обновить «все документы» без использования запроса { "_id" : { $exists : true } }

ответ

9

Is this possible, and if so, what am I doing wrong in my update?

Нет. В общем MongoDB работает только с обновлением объектов верхнего уровня.

Исключение составляет $ positional operator. Из документов: Use this to find an array member and then manipulate it.

Однако в вашем случае вы хотите изменить все элементы в массиве. Так что это не то, что вам нужно.

Bonus karma for anyone who can tell me a cleaner why to update "all documents"

Попробуйте db.coll.update(query, update, false, true), это выдает обновление «multi». Это последнее true - это то, что делает его мульти.

Is this possible,

У вас есть два варианта здесь:

  1. Написать цикл for для выполнения обновления. Он будет в основном быть вложенным циклом for, один для циклического преобразования данных, а другой - в подматрицу. Если у вас много данных, вы захотите написать, что это ваш выбор (и, возможно, многопоточный он).
  2. Напишите свой код для обработки reviewed как обнуляемый. Напишите данные таким образом, чтобы при нахождении фотографии с reviewed не определено, это должно быть false. Затем вы можете установить поле соответствующим образом и передать его обратно в БД.

Метод № 2 - это то, к чему вы должны привыкнуть. По мере того, как ваши данные растут, и вы добавляете поля, становится сложно «вернуть обратно» все старые данные. Это похоже на проблему выдачи изменения схемы в SQL, когда у вас есть 1B элементов в БД.

Вместо этого сделайте свой код устойчивым к null и научитесь относиться к нему по умолчанию.

Опять же, это все еще не решение, которое вы ищете.

+0

Хороший ответ. Чтобы уточнить, что я искал для «бонуса», был способ обновить все документы «простым» запросом (что-то более простое, чем «{« _id »: {$ exists: true}}». Я понимаю, что «multi» «param», но мне все еще нужен запрос, который соответствует всем документам. Я думал, что «{}» будет соответствовать всем документам, но я так не думаю? –

+0

И нет, это не «решение», а Хорошее объяснение того, почему я просто не могу добиться того, что я ищу, с завершенной версией mongodb (2.0.2). Если решение станет доступным, отправьте другой ответ для будущих пользователей. –

-1

Вы можете сделать это

(null, {$set : {"photos.reviewed" : false} }, false, true) 

Первый параметр не является пустым: нет спецификация = любой элемент в коллекции.

"photos.reviewed" должен быть объявлен как строка для обновления подполя.

+2

вы не можете этого сделать. с 'assert failed: нужен запрос' – Warz

-1

Вы можете сделать так:

db.person.update({}, $set:{name.surname:null}, false, true); 
-1

Старый сейчас тема, но это просто прекрасно работали с Монго 3.0.6:

db.users.update({ _id: ObjectId("55e8969119cee85d216211fb") }, { $set: {"settings.pieces": "merida"} })

В моем случае пользовательского объекта выглядит

{ _id: 32, name: "foo", ..., settings: { ..., pieces: "merida", ...} } 
+0

У вас нет массива, как в вопросе. – Gramic

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