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, но это зло, но это заблокировало бы это обновление до одного потока.