Mongoose: findOneAndUpdate не возвращает обновленный документ

257

Ниже мой код

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

var Cat = mongoose.model('Cat', {
    name: String,
    age: {type: Number, default: 20},
    create: {type: Date, default: Date.now} 
});

Cat.findOneAndUpdate({age: 17}, {$set:{name:"Naomi"}},function(err, doc){
    if(err){
        console.log("Something wrong when updating data!");
    }

    console.log(doc);
});

У меня уже есть какая-то запись в моей базе данных Монго, и я хотел бы запустить этот код, чтобы обновить имя, для которого 17 лет, а затем распечатать результат в конце кода.

Однако, почему я все еще получаю тот же результат из консоли (не измененное имя), но когда я иду в командную строку mongo db и набираю " db.cats.find();" Результат пришел с измененным именем.

Затем я снова запускаю этот код, и результат изменяется.

Мой вопрос: если данные были изменены, то почему я все еще получил оригинальные данные в первый раз, когда console.log их.

Мечты
источник

Ответы:

528

Почему это происходит?

По умолчанию возвращается исходный, неизмененный документ. Если вы хотите, чтобы новый, обновленный документ был возвращен, вы должны передать дополнительный аргумент: объект со newсвойством, установленным в true.

Из документов Мангуста :

Запрос # findOneAndUpdate

Model.findOneAndUpdate(conditions, update, options, (error, doc) => {
  // error: any errors that occurred
  // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
});

Доступные Варианты

  • new: bool - если true , вернуть измененный документ, а не оригинал. по умолчанию false (изменено в 4.0)

Решение

Передайте, {new: true}если вы хотите обновить результат в docпеременной:

//                                                         V--- THIS WAS ADDED
Cat.findOneAndUpdate({age: 17}, {$set:{name:"Naomi"}}, {new: true}, (err, doc) => {
    if (err) {
        console.log("Something wrong when updating data!");
    }

    console.log(doc);
});
XCS
источник
15
Мне кажется, что это не работает, он по-прежнему возвращает старый документ с новым: true.
PDN
@PDN Какая у вас версия mongoose / mongo? Это может мешать, как это работает.
Коул Эриксон
5
имеет смысл для меня, так как у вас уже есть доступ к новому документу
danday74
3
у меня это сработало, я использую Moogose версии 4.6.3, спасибо
cesar andavisa
2
Использует нодже MongoDB Native -{ returnOriginal: false }
Ник Грейли
78

Для тех, кто использует драйвер Node.js вместо Mongoose, вы захотите использовать {returnOriginal:false}вместо {new:true}.

Педро Хоэль Карвалью
источник
1
Спасибо! Это работает для меня версия узла mongodb 2.2.27
Кевин Нг
6
Это своего рода идиотский API. Почему бы не использовать те же подписи для Mongoose, что и для нативного API? Почему бы не вернуть обновленный документ по умолчанию? Мангуст - одна из самых раздражающих библиотек, которыми я пользуюсь каждый день.
Askdesigners
56

Таким образом, «findOneAndUpdate» требует опции для возврата оригинального документа. И, вариант:

Оболочка MongoDB

{returnNewDocument: true}

Ссылка: https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate/

Мангуста

{new: true}

Ссылка: http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate

Node.js API драйвера MongoDB:

{returnOriginal: false}

Ссылка: http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#findOneAndUpdate

Цунео Йошиока
источник
Ларавел:'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER
Джакомо Альзетта
39

По умолчанию findOneAndUpdate возвращает исходный документ. Если вы хотите, чтобы он возвратил измененный документ, передайте объект параметров { new: true }в функцию:

Cat.findOneAndUpdate({ age: 17 }, { $set: { name: "Naomi" } }, { new: true }, function(err, doc) {

});
hthserhs
источник
2
почему _idноль?
Чови
14

Для тех, кто наткнулся на это, используя стиль ES6 / ES7 с собственными обещаниями, вот шаблон, который вы можете принять ...

const user = { id: 1, name: "Fart Face 3rd"};
const userUpdate = { name: "Pizza Face" };

try {
    user = await new Promise( ( resolve, reject ) => {
        User.update( { _id: user.id }, userUpdate, { upsert: true, new: true }, ( error, obj ) => {
            if( error ) {
                console.error( JSON.stringify( error ) );
                return reject( error );
            }

            resolve( obj );
        });
    })
} catch( error ) { /* set the world on fire */ }
Ассаф Молдавский
источник
15
Mongoose вернет обещание, если вы не предоставите функцию обратного вызова. Нет необходимости создавать собственное обещание!
Joeytwiddle
1
@joeytwiddle Mongoose не вернет Обещание, если вы не предоставите обратный вызов. Вместо этого он возвращает объект Query, который предоставляет только небольшое подмножество API Promise. Это в соответствии с документацией Mongoose.
Джейми Риддинг
13

Это обновленный код для findOneAndUpdate. Оно работает.

db.collection.findOneAndUpdate(    
  { age: 17 },      
  { $set: { name: "Naomi" } },      
  {
     returnNewDocument: true
  }    
)
Джобин Мэтью
источник
9

Мангуста здесь. Вам нужно установить newопцию true(или, что то же самое, returnOriginalчтобы false)

await User.findOneAndUpdate(filter, update, { new: true });

// Equivalent
await User.findOneAndUpdate(filter, update, { returnOriginal: false });

См. Документацию MongoosefindOneAndUpdate() и это руководство по обновлению документов в Mongoose .

vkarpov15
источник
Я ошибся, чтобы написать returnNewDocument вместо просто нового. Спасибо за помощь!
user1111527
3

Если вы хотите вернуть измененный документ, вам нужно установить опцию {new:true}API-ссылку, которую вы можете использоватьCat.findOneAndUpdate(conditions, update, options, callback) // executes

Взятые официальным API Mongoose http://mongoosejs.com/docs/api.html#findoneandupdate_findOneAndUpdate, вы можете использовать следующие параметры

A.findOneAndUpdate(conditions, update, options, callback) // executes
A.findOneAndUpdate(conditions, update, options)  // returns Query
A.findOneAndUpdate(conditions, update, callback) // executes
A.findOneAndUpdate(conditions, update)           // returns Query
A.findOneAndUpdate()                             // returns Query

Еще одна реализация, которая не отражена на официальной странице API и которую я предпочитаю использовать, - это Promiseбазовая реализация, которая позволяет вам иметь место, .catchгде вы можете справиться со всеми вашими различными ошибками.

    let cat: catInterface = {
        name: "Naomi"
    };

    Cat.findOneAndUpdate({age:17}, cat,{new: true}).then((data) =>{
        if(data === null){
            throw new Error('Cat Not Found');
        }
        res.json({ message: 'Cat updated!' })
        console.log("New cat data", data);
    }).catch( (error) => {
        /*
            Deal with all your errors here with your preferred error handle middleware / method
         */
        res.status(500).json({ message: 'Some Error!' })
        console.log(error);
    });
Джонатан Турфт
источник
2

Ниже показан запрос для мангуста findOneAndUpdate. Здесь new: trueиспользуется для получения обновленного документа и fieldsдля получения определенных полей.

например. findOneAndUpdate(conditions, update, options, callback)

await User.findOneAndUpdate({
      "_id": data.id,
    }, { $set: { name: "Amar", designation: "Software Developer" } }, {
      new: true,
      fields: {
        'name': 1,
        'designation': 1
      }
    }).exec();
Сурабх Хурана
источник
1

Я знаю, я уже опоздал, но позвольте мне добавить мой простой и рабочий ответ здесь

const query = {} //your query here
const update = {} //your update in json here
const option = {new: true} //will return updated document

const user = await User.findOneAndUpdate(query , update, option)
Алджон Ямаро
источник