Mongodb upsert только обновляет выбранные поля, но вставляет все
Я пытаюсь использовать upsert в MongoDB для обновления одного поля в документе, если он найден или вставляет целый новый документ с большим количеством полей. Проблема в том, что мне кажется, что MongoDB либо заменяет каждое поле, либо вставляет подмножество полей в свою операцию upsert, т.е. Не может вставлять больше полей, чем это действительно хочет обновить.
Я хочу сделать следующее:
- Я запрашиваю одно уникальное значение
- Если документ уже существует, только новое значение времени (позволяет вызывать его "lastseen" ) обновляется до нового значения
- Если документ не существует, я добавлю его с длинным списком разных пар ключ/значение, которые должны оставаться статическими в течение оставшейся части его срока службы.
Давайте проиллюстрируем:
В этом примере из моего понимания будет обновлена дата "lastseen" , если "имя" найдено, но если "имя" не найдено, оно будет только вставлять "name" + "lastseen" .
db.somecollection.update({name: "some name"},{ $set: {"lastseen": "2012-12-28"}}, {upsert:true})
Если я добавил больше полей (пары ключ/значение) ко второму аргументу и сбросил значение $set, тогда каждое поле будет заменено при обновлении, но будет иметь желаемый эффект при вставке. Есть ли что-то вроде $insert или подобное для выполнения операций только при вставке?
Мне кажется, что я могу получить только одно из следующего:
- Правильное поведение при обновлении, но будет вставлять документ только подмножеством желаемых полей, если документ не существует
- Правильное поведение вставки, но затем будет перезаписано все существующие поля, если документ уже существует.
Правильно ли я понимаю? Если да, возможно ли это решить с помощью одной операции?
Ответы
Ответ 1
MongoDB 2.4 имеет $setOnInsert
db.somecollection.update(
{name: "some name"},
{
$set: {
"lastseen": "2012-12-28"
},
$setOnInsert: {
"firstseen": <TIMESTAMP> # set on insert, not on update
}
},
{upsert:true}
)
Ответ 2
Для этого есть запрос функции (https://jira.mongodb.org/browse/SERVER-340), который разрешен в 2.3. Нечетные выпуски на самом деле выпущены dev, поэтому это будет в стабильной версии 2.4.
Таким образом, в текущих стабильных версиях нет реального способа сделать это. Я боюсь, что единственный способ состоит в том, чтобы фактически выполнить 3 условных запроса atm: 1, чтобы проверить строку, а затем if
либо вставить, либо обновить.
Я полагаю, что если бы у вас были настоящие проблемы с блокировкой, вы могли бы сделать эту функцию с единственным JS, но это зло, но это заблокировало бы это обновление до одного потока.