Возможно, пришло время, возможно, это я тону в редких документах и не могу обернуться вокруг концепции обновления в Mongoose :)
Вот сделка:
У меня есть контактная схема и модель (укороченные свойства):
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var mongooseTypes = require("mongoose-types"),
useTimestamps = mongooseTypes.useTimestamps;
var ContactSchema = new Schema({
phone: {
type: String,
index: {
unique: true,
dropDups: true
}
},
status: {
type: String,
lowercase: true,
trim: true,
default: 'on'
}
});
ContactSchema.plugin(useTimestamps);
var Contact = mongoose.model('Contact', ContactSchema);
Я получаю запрос от клиента, содержащий необходимые мне поля, и использую свою модель таким образом:
mongoose.connect(connectionString);
var contact = new Contact({
phone: request.phone,
status: request.status
});
И теперь мы добрались до проблемы:
- Если я позвоню,
contact.save(function(err){...})
я получу сообщение об ошибке, если контакт с тем же номером телефона уже существует (как и ожидалось - уникальный) - Я не могу позвонить
update()
по контакту, так как этот метод не существует в документе - Если я вызываю update для модели:
Contact.update({phone:request.phone}, contact, {upsert: true}, function(err{...})
я попадаю в бесконечный цикл некоторых видов, поскольку реализация обновления Mongoose явно не хочет, чтобы объект был вторым параметром. - Если я делаю то же самое, но во втором параметре я передаю ассоциативный массив свойств запроса,
{status: request.status, phone: request.phone ...}
он работает - но тогда у меня нет ссылки на конкретный контакт и я не могу выяснить егоcreatedAt
иupdatedAt
свойства.
Итак, в конце концов, после всего, что я пытался: дать документ contact
, как мне обновить его, если он существует, или добавить его, если его нет?
Спасибо за ваше время.
javascript
mongodb
node.js
mongoose
Путешествующий техник
источник
источник
pre
дляsave
?Ответы:
Mongoose теперь поддерживает это с помощью findOneAndUpdate (вызывает MongoDB findAndModify ).
Опция upsert = true создает объект, если он не существует. по умолчанию ложно .
В старых версиях Mongoose не поддерживает эти ловушки с помощью этого метода:
источник
Я просто сжег 3 часа, пытаясь решить ту же проблему. В частности, я хотел «заменить» весь документ, если он существует, или вставить его другим способом. Вот решение:
Я создал проблему на странице проекта Mongoose с просьбой добавить информацию об этом в документы.
источник
MyModel.update({ age: { $gt: 18 } }, { oldEnough: true }, fn);
иMyModel.update({ name: 'Tobi' }, { ferret: true }, { multi: true }, fn);
Вы были близки с
но ваш второй параметр должен быть объектом с оператором модификации, например
источник
{$set: ... }
часть, так как она автоматически формируется во время моего чтенияЯ ждала достаточно долго и ответа не было. В конце концов отказались от всего подхода обновления / вставки и пошли с:
Это работает? Ага. Доволен ли я этим? Возможно нет. 2 вызова БД вместо одного.
Надеюсь, будущая реализация Mongoose предложит
Model.upsert
функцию.источник
runValidators: true
во время обновления: обновление документы (однако, обновление валидаторы работать только на$set
и$unset
операций).upsert()
быть доступным на всех моделях. stackoverflow.com/a/50208331/1586406Очень элегантное решение, которое вы можете достичь, используя цепочку обещаний:
источник
(model) => { return model.save(); }
какmodel => model.save()
, а также(err) => { res.send(err); }
какerr => res.send(err)
;)Я хранитель Мангуста. Более современный способ использовать документ - использовать
Model.updateOne()
функцию .Если вам нужен загруженный документ, вы можете использовать
Model.findOneAndUpdate()
Главное, что вы должны поместить уникальные свойства в
filter
параметре вupdateOne()
илиfindOneAndUpdate()
, а другие свойства вupdate
параметре.Вот учебник по загрузке документов с Mongoose .
источник
Я создал учетную запись StackOverflow просто, чтобы ответить на этот вопрос. После бесплодного поиска в сети я просто что-то написал сам. Вот как я это сделал, чтобы его можно было применить к любой модели мангуста. Либо импортируйте эту функцию, либо добавьте ее непосредственно в код, где вы выполняете обновление.
Затем, чтобы сохранить документ Мангуста, сделайте следующее:
Это решение может потребовать 2 вызова БД, однако вы получаете
Просто помните, что объект назначения всегда будет переопределять источник, даже если источник имеет существующее значение
Кроме того, для массивов, если существующий объект имеет более длинный массив, чем тот, который его заменяет, значения в конце старого массива останутся. Простой способ сохранить весь массив - это установить старый массив как пустой массив перед загрузкой, если это то, что вы собираетесь делать.
ОБНОВЛЕНИЕ - 16.01.2016 Я добавил дополнительное условие: если существует массив примитивных значений, Mongoose не понимает, что массив обновляется без использования функции «set».
источник
if(_.isObject(value) && _.keys(value).length !== 0) {
условие охраны, чтобы остановить переполнение стека. Lodash 4+ здесь, кажется, преобразует не объектные значения в объекты вkeys
вызове, поэтому рекурсивная защита всегда была истинной. Может быть, есть лучший способ, но сейчас он почти работает для меня ...Мне нужно было обновить / вставить документ в одну коллекцию, и я создал новый объектный литерал, подобный этому:
состоит из данных, которые я получаю откуда-то еще в моей базе данных, а затем вызвать обновление модели
это результат, который я получаю после первого запуска скрипта:
И это вывод, когда я запускаю скрипт во второй раз:
Я использую версию Мангуста 3.6.16
источник
Вот лучший подход к решению метода обновления в mongoose, вы можете проверить Scotch.io для более подробной информации. Это определенно сработало для меня!
источник
В версии 2.6 появилась ошибка, которая также влияет на версию 2.7.
Упсерт корректно работал на 2.4
https://groups.google.com/forum/#!topic/mongodb-user/UcKvx4p4hnY https://jira.mongodb.org/browse/SERVER-13843
Посмотрите, он содержит важную информацию
ОБНОВЛЕНО:
Это не значит, что upsert не работает. Вот хороший пример того, как его использовать:
источник
Вы можете просто обновить запись с этим и получить обновленные данные в ответ
источник
это сработало для меня.
источник
Вот самый простой способ создания / обновления, а также вызов промежуточного программного обеспечения и валидаторов.
источник
Для тех, кто прибывает сюда, все еще ищущих хорошее решение для «апперсинга» с поддержкой хуков, это то, что я протестировал и работал. Это все еще требует 2 вызовов БД, но намного более стабильно, чем все, что я пробовал в одном вызове.
источник
Если генераторы доступны, это становится еще проще:
источник
Никакое другое решение не помогло мне. Я использую почтовый запрос и обновляю данные, если они найдены, либо вставьте их, а также _id отправляется с телом запроса, которое необходимо удалить.
источник
источник
источник
Следуя ответу Traveling Tech Guy , который уже великолепен, мы можем создать плагин и прикрепить его к mongoose после его инициализации, чтобы
.upsert()
он был доступен на всех моделях.plugins.js
db.js
Тогда вы можете сделать что-то вроде
User.upsert({ _id: 1 }, { foo: 'bar' })
илиYouModel.upsert({ bar: 'foo' }, { value: 1 })
когда захотите.источник
Я просто вернулся к этой проблеме через некоторое время и решил опубликовать плагин, основанный на ответе Аарона Маста.
https://www.npmjs.com/package/mongoose-recursive-upsert
Используйте его как плагин мангусты. Он устанавливает статический метод, который будет рекурсивно объединять переданный объект.
источник
Этот coffeescript работает для меня с Node - хитрость заключается в том, что _id get лишается своей обертки ObjectID при отправке и возврате из клиента, и поэтому его необходимо заменить для обновлений (когда _id не предоставлен, save вернется к вставке и добавлению один).
источник
основываться на том, что Мартин Куздович написал выше. Я использую следующее для обновления с помощью mongoose и глубокого слияния объектов json. Наряду с функцией model.save () в mongoose это позволяет mongoose выполнить полную проверку, даже если она использует другие значения в json. для этого требуется пакет Deepmerge https://www.npmjs.com/package/deepmerge . Но это очень легкий пакет.
источник
req.body
как есть, перед тестированием на внедрение NoSQL (см. Owasp.org/index.php/Testing_for_NoSQL_injection ).Прочитав посты выше, я решил использовать этот код:
если r равно нулю, мы создаем новый элемент. В противном случае используйте upsert в обновлении, потому что обновление не создает новый элемент.
источник