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.

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

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}.


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


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) {

});

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 */ }

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

9

Mantenedor de mangusto aqui. Você precisa definir a newopção para true(ou, equivalentemente, returnOriginalpara false)

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

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

Consulte os documentos do MongoosefindOneAndUpdate() e este tutorial sobre atualização de documentos no Mongoose .


Errei ao escrever returnNewDocument em vez de apenas new. obrigado pela ajuda!
user1111527

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

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

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)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.