Mongoose: findOneAndUpdate não retorna documento atualizado

256

Abaixo está o meu código

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);
});

Eu já tenho algum registro no meu banco de dados mongo e gostaria de executar esse código para atualizar o nome para a idade de 17 anos e depois imprimir o resultado no final do código.

No entanto, por que ainda recebo o mesmo resultado do console (não o nome modificado), mas quando vou para a linha de comando do mongo db e digito " db.cats.find();". O resultado veio com nome modificado.

Então volto a executar esse código novamente e o resultado é modificado.

Minha pergunta é: se os dados foram modificados, por que ainda obtive dados originais na primeira vez em que console.log os dados.

Sonhos
fonte

Respostas:

527

Por que isso acontece?

O padrão é retornar o documento original inalterado . Se você deseja que o documento novo e atualizado seja devolvido, é necessário passar um argumento adicional: um objeto com a newpropriedade definida como true.

Dos documentos do mangusto :

Consulta # 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`
});

Opções disponíveis

  • new: bool - se verdadeiro , retorne o documento modificado em vez do original. o padrão é false (alterado em 4.0)

Solução

Passe {new: true}se você deseja o resultado atualizado na docvariável:

//                                                         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
fonte
15
Isso parece estar quebrado para mim, mas ainda retorna o documento antigo com new: true.
PDN 21/04
@PDN Qual versão do mongoose / mongo você possui? Isso pode estar interferindo na maneira como funciona.
Cole Erickson
5
faz sentido para mim desde que você já tem acesso ao novo documento
danday74
3
ele trabalhou para mim, eu estou usando moogose versão 4.6.3, graças
cesar andavisa
2
NodeJs MongoDB Native usa -{ returnOriginal: false }
Nick Grealy
78

Para qualquer um usando o driver Node.js vez de Mongoose, você vai querer usar {returnOriginal:false}em vez de {new:true}.

Pedro Hoehl Carvalho
fonte
1
Obrigado! Isso funciona para mim mongodb nó versão 2.2.27
Kevin Ng
6
Esse é um tipo de API idiota. Por que não usar as mesmas assinaturas do Mongoose para a API nativa? Por que não retornar o documento atualizado por padrão? Mongoose é uma das bibliotecas mais irritantes que uso todos os dias.
Askdesigners
56

Portanto, "findOneAndUpdate" requer uma opção para retornar o documento original. E, a opção é:

Shell MongoDB

{returnNewDocument: true}

Ref: https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndUpdate/

Mangusto

{new: true}

Ref: http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate

API do driver MongoDB do Node.js:

{returnOriginal: false}

Ref: http://mongodb.github.io/node-mongodb-native/3.0/api/Collection.html#findOneAndUpdate

Tsuneo Yoshioka
fonte
Laravel:'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER
Giacomo Alzetta
39

Por padrão, findOneAndUpdate retorna o documento original. Se você deseja retornar o documento modificado, passe um objeto de opções { new: true }para a função:

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

});
hthserhs
fonte
2
por que é _idnulo?
chovy
14

Para quem se deparou com isso usando o estilo ES6 / ES7 com promessas nativas, aqui está um padrão que você pode adotar ...

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 */ }
Assaf Moldavsky
fonte
15
O Mongoose retornará uma promessa se você não fornecer uma função de retorno de chamada. Não há necessidade de criar sua própria promessa!
Joeytwiddle 19/09/17
1
@joeytwiddle O Mongoose não retornará uma promessa se você não fornecer um retorno de chamada. Em vez disso, ele retorna um objeto de consulta que fornece apenas um pequeno subconjunto da API do Promise. Isso está de acordo com a documentação do Mongoose.
Jamie Ridding
13

Este é o código atualizado para findOneAndUpdate. Funciona.

db.collection.findOneAndUpdate(    
  { age: 17 },      
  { $set: { name: "Naomi" } },      
  {
     returnNewDocument: true
  }    
)
Jobin Mathew
fonte
3

Se você quiser devolver o documento alterado, precisará definir a {new:true}referência da API da opção que pode usarCat.findOneAndUpdate(conditions, update, options, callback) // executes

Tomado pela API oficial do Mongoose http://mongoosejs.com/docs/api.html#findoneandupdate_findOneAndUpdate, você pode usar os seguintes parâmetros

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

Outra implementação que não está expressa na página oficial da API e é o que eu prefiro usar é a Promiseimplementação básica que permite que você tenha .catchonde você pode lidar com todos os seus vários erros lá.

    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);
    });
Jonathan Thurft
fonte
2

Abaixo mostra a consulta para mangusto findOneAndUpdate. Aqui new: trueé usado para obter o documento atualizado efields é usado para obter campos específicos.

por exemplo. 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();
Sourabh Khurana
fonte
1

Eu sei, eu já estou atrasado, mas deixe-me adicionar minha resposta simples e prática aqui

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)
Aljohn Yamaro
fonte