2013-08-21 2 views
6

Примечание: Для выполнения кодов используйте оболочку mongodb.Обновить/удалить поддокумент в коллекции MongoDB

Скажем, у меня есть один студенческий документ, как показано ниже

{ 
    "_id" : 4, 
"grades" : [ 
    { 
     "grade" : 80, 
     "mean" : 75, 
     "std" : 8 
    }, 
    { 
     "grade" : 85, 
     "mean" : 90, 
     "std" : 5 
    }, 
    { 
     "grade" : 85, 
     "mean" : 90, 
     "std" : 5 
    }, 
    { 
     "grade" : 85, 
     "mean" : 95, 
     "std" : 6 
    }, 
    { 
     "grade" : 90, 
     "mean" : 85, 
     "std" : 5 
    } 
] 
} 

У нас есть 2 проблемы:

Проблемных 1: позволяет сказать, что вы хотите обновите все поддокументы с _id = & сортов. класс = 85 & & grades.std = 5, с std = 6, вы будете писать следующим образом

db.students.update({'$and':[ { _id: 4},{ "grades.grade": 85 }, {"grades.std": 5 } ]}, { $set: { "grades.$.std" : 6 } }); 

Теперь, если выполняемая выше заявление несколько раз (3 раза), то в идеале она должна обновлять 2-й, 3-й поддокументов

Но последний поддокументу также получать обновленные обусловлено это имеет зЬй = 5 матча, но мы дали условие как $ и не $ или, то как последний документ обновляется?

Задача 2: Теперь предположим, что вы хочет удалить сам поддокумент соответствия критериям запроса. Я попробовал следующее заявление

db.students.update({_id:4,'grades.grade':85},{'$unset':{'grades.$':1}}) 

, потому что $ незаданы поставит нуль в случае суб-документы/массивов, как решить эту проблему?

Как копировать на консоль mongodb?

db.students.insert({ "_id" : 4, "grades" : [ { grade: 80, mean: 75, std: 8 }, { grade: 85, mean: 90, std: 5 }, { grade: 85, mean: 90, std: 5 }, { grade: 85, mean: 95, std: 6 }, { grade: 90, mean: 85, std: 5 } ] }); 

ответ

10

Оператор «$» обновляет только первый матч так дал:

db.students.insert({ "_id" : 4, "grades" : [ 
    { grade: 80, mean: 75, std: 8 }, 
    { grade: 85, mean: 90, std: 5 }, 
    { grade: 85, mean: 90, std: 5 }, 
    { grade: 85, mean: 95, std: 6 }, 
    { grade: 90, mean: 85, std: 5 } ]}); 

Для обновления вы должны предназначаться с $elemMatch так:

db.students.update({ _id: 4, "grades": {$elemMatch: {"grade": 85, "std": 5 }}}, 
        { $set: { "grades.$.std" : 6 } }); 

Однако, у вас есть два класса, которые соответствуют {"grades.grade": 85, "grades.std": 5} и $ только обновляет первый, так что вам нужно зацикливаться до тех пор, пока не будет обновлено:

db.students.update({ _id: 4, "grades": {$elemMatch: {"grade": 85, "std": 5 }}}, 
        { $set: { "grades.$.std" : 6 } }) 
while (db.getLastErrorObj()['n'] > 0) { 
    db.students.update({ _id: 4, "grades": {$elemMatch: {"grade": 85, "std": 5 }}}, 
         { $set: { "grades.$.std" : 6 } }) 
} 

Проблема 2: То же самое относится - вы должны петли для $pull согласующих элементов:

db.students.update({_id:4,'grades': {$elemMatch: {'grade':85}}}, {'$pull': {'grades': {'grade':85}}}) 
+0

Спасибо за первый ответ на вопрос, я уже пробовал с ответом @drmirror. $ pull установит значение null в случае субдокументов, тогда мне нужно выполнить 2 оператора обновления один для его обновления до нулевого значения, другой для удаления нулевого значения из поддокумента. Возможно ли это для одного заявления об обновлении? –

+0

В 2.4 его вытягивание вспомогательных документов и не задание как null. – Ross

+0

чрезвычайно Извините, мой плохой ... это сработало ... Большое спасибо –

2

Вы должны использовать $elemMatch, чтобы соответствовать внутри массива. Правила запроса в MongoDB указывают, что для условий элементов массива любой элемент массива, в котором выполняется какое-либо из условий, считается совпадением. С $elemMatch все условия должны совпадать на одном элементе.

+0

Не могли бы вы записать заявление оболочки для этого же? –

+0

Можно ли решить вторую проблему? –

+0

спасибо .. я пробовал с $ elemMatch, и он работает. Но для второй проблемы. Я не хочу выполнять 2 инструкции обновления только для удаления одного вложенного документа. Есть ли способ? по одному исполнению оператора –

0

Точечные обозначения соответствуют документам, согласно которым его критерии могут быть выполнены в любом из элементов массива.

Если вы хотите, чтобы соответствовать только документы, которые соответствуют всем Вашим критериям в одном элементе массива (по крайней мере), то, как drmirror уже ответили, вы должны использовать оператор $ elemMatch, смотри также: $elemMatch Operator

В вашем случае это будет:

db.students.update({'$and':[ { _id: 4},{ "grades":{"$elemMatch": {"grade": 85, "std": 5 }}} ]}, { $set: { "grades.$.std" : 6 } }); 

Для второй части вашего вопроса, как удалить элементы массива, см. Следующий пост.

In mongoDb, how do you remove an array element by its index

Короче говоря, это операция два шага, что первые наборы для null элемента (как вы уже делаете), а затем это $ pull (ы) его.

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