MongoDB atomic "findOrCreate": findOne, вставить, если не существует, но не обновлять
как говорится в заголовке, я хочу выполнить поиск (один) для документа, посредством _id, и если он не существует, создайте его, затем, было ли оно найдено или было создано, вернуть его в обратном вызове.
Я не хочу обновлять его, если он существует, поскольку я читал findAndModify. Я видел много других вопросов по Stackoverflow относительно этого, но опять же, не хочу ничего обновлять.
Я не уверен, создавая (из-за отсутствия), ТО, на самом деле это обновление, о котором все говорят, все это путается: (
Ответы
Ответ 1
Начиная с MongoDB 2.4, больше не нужно полагаться на уникальный индекс (или любой другой обходной путь) для атомных findOrCreate
подобных операций.
Это благодаря оператору $setOnInsert
, начиная с 2.4, что позволяет указывать обновления, которые должны выполняться только при вставке документов.
Это, в сочетании с опцией upsert
, означает, что вы можете использовать findAndModify
для выполнения атомной операции findOrCreate
.
db.collection.findAndModify({
query: { _id: "some potentially existing id" },
update: {
$setOnInsert: { foo: "bar" }
},
new: true, // return new doc if one is upserted
upsert: true // insert the document if it does not exist
})
Поскольку $setOnInsert
влияет только на вставленные документы, если существующий документ найден, модификация не будет выполнена. Если документ не существует, он будет поддерживать один с указанным _id, а затем выполнить установку только вставки. В обоих случаях документ возвращается.
Ответ 2
Его немного грязно, но вы можете просто вставить его.
Убедитесь, что на нем есть уникальный индекс (если вы используете _id, это нормально, оно уже уникально).
Таким образом, если элемент уже присутствует, он вернет исключение, которое вы можете поймать.
Если он отсутствует, новый документ будет вставлен.
Обновлено: подробное объяснение этой техники в Документация MongoDB
Ответ 3
Версии драйверов> 2
Используя последнюю версию драйвера (> версия 2), вы будете использовать findOneAndUpdate, так как findAndModify
устарела. Новый метод принимает 3 аргумента: filter
, объект update
(который содержит свойства по умолчанию, которые должны быть вставлены для нового объекта) и options
которых необходимо указать операцию upsert.
Используя синтаксис обещания, это выглядит так:
const result = await collection.findOneAndUpdate(
{ _id: new ObjectId(id) },
{
$setOnInsert: { foo: "bar" },
},
{
returnOriginal: false,
upsert: true,
}
);
const newOrUpdatedDocument = result.value;
Ответ 4
Вот что я сделал (Ruby MongoDB driver):
$db[:tags].update_one({:tag => 'flat'}, {'$set' => {:tag => 'earth' }}, { :upsert => true })}
Он обновит его, если он существует, и вставьте его, если это не так.