Mangosta: findOneAndUpdate no devuelve el documento actualizado

257

Abajo está mi 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);
});

Ya tengo algún registro en mi base de datos de mongo y me gustaría ejecutar este código para actualizar el nombre para el que tiene 17 años y luego imprimir el resultado al final del código.

Sin embargo, por qué sigo obteniendo el mismo resultado de la consola (no el nombre modificado) pero cuando voy a la línea de comando de mongo db y escribo " db.cats.find();". El resultado vino con nombre modificado.

Luego vuelvo a ejecutar este código nuevamente y el resultado se modifica.

Mi pregunta es: si se modificaron los datos, ¿por qué todavía tengo datos originales por primera vez cuando console.log?

Sueños
fuente

Respuestas:

528

¿Por qué pasa esto?

El valor predeterminado es devolver el documento original sin modificaciones . Si desea que se devuelva el documento nuevo y actualizado, debe pasar un argumento adicional: un objeto con la newpropiedad establecida en true.

De los documentos de mangosta :

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

Opciones Disponibles

  • new: bool: si es verdadero , devuelve el documento modificado en lugar del original. el valor predeterminado es falso (cambiado en 4.0)

Solución

Pase {new: true}si desea el resultado actualizado en la docvariable:

//                                                         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
fuente
15
Esto parece estar roto para mí, todavía devuelve el documento antiguo con nuevo: verdadero.
PDN
@PDN ¿Qué versión de mangosta / mongo tienes? Eso podría estar jugando con cómo funciona.
Cole Erickson
55
tiene sentido para mí ya que ya tiene acceso al nuevo documento
danday74
3
funcionó para mí, estoy usando moogose versión 4.6.3, gracias
cesar andavisa
2
Usos nativos de NodeJs MongoDB -{ returnOriginal: false }
Nick Grealy
78

Para cualquiera que use el controlador Node.js en lugar de Mongoose, querrá usarlo en {returnOriginal:false}lugar de {new:true}.

Pedro Hoehl Carvalho
fuente
1
¡Gracias! Esto funciona para mí nodo mongodb versión 2.2.27
Kevin Ng
66
Esta es una especie de API idiota. ¿Por qué no usar las mismas firmas para Mongoose que la API nativa? ¿Por qué no devolver el documento actualizado de forma predeterminada? La mangosta es una de las librerías más irritantes que uso todos los días.
Askdesigners
56

Entonces, "findOneAndUpdate" requiere una opción para devolver el documento original. Y, la opción es:

Shell MongoDB

{returnNewDocument: true}

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

Mangosta

{new: true}

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

Node.js MongoDB Driver API:

{returnOriginal: false}

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

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

Por defecto, findOneAndUpdate devuelve el documento original. Si desea que devuelva el documento modificado, pase un objeto de opciones { new: true }a la función:

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

});
hthserhs
fuente
2
¿Por qué es _idnulo?
chovy
14

Para quien tropezó con esto usando el estilo ES6 / ES7 con promesas nativas, aquí hay un patrón que puede adoptar ...

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
fuente
15
Mongoose le devolverá una promesa si no proporciona una función de devolución de llamada. ¡No hay necesidad de crear tu propia promesa!
joeytwiddle
1
@joeytwiddle Mongoose no devolverá una Promesa si no proporciona una devolución de llamada. En cambio, devuelve un objeto Query que proporciona solo un pequeño subconjunto de la API Promise. Esto está de acuerdo con la documentación de Mongoose.
Jamie Ridding
13

Este es el código actualizado para findOneAndUpdate. Funciona.

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

Mantenedor de mangosta aquí. Debe establecer la newopción en true(o, equivalentemente, returnOriginalen false)

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

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

Consulte los documentos de MongoosefindOneAndUpdate() y este tutorial sobre la actualización de documentos en Mongoose .

vkarpov15
fuente
Me he equivocado al escribir returnNewDocument en lugar de solo new. ¡gracias por la ayuda!
user1111527
3

Si desea devolver el documento alterado, debe establecer la opción de {new:true}referencia de API que puede usarCat.findOneAndUpdate(conditions, update, options, callback) // executes

Tomado por la API oficial de Mongoose http://mongoosejs.com/docs/api.html#findoneandupdate_findOneAndUpdate puede usar los siguientes 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

Otra implementación que no está expresada en la página oficial de la API y es la que prefiero usar es la Promiseimplementación base que le permite tener .catchdónde puede lidiar con todos sus diversos errores allí.

    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
fuente
2

A continuación se muestra la consulta de mangostas findOneAndUpdate. Aquí new: truese utiliza para obtener el documento actualizado y fieldsse utiliza para obtener campos específicos.

p.ej. 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
fuente
1

Lo sé, ya llego tarde, pero déjenme agregar mi respuesta simple y funcional aquí

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
fuente