¿Cómo actualizo/actualizo un documento en Mongoose?

Resuelto Traveling Tech Guy asked hace 13 años • 23 respuestas

Tal vez sea el momento, tal vez sea yo ahogándome en documentación escasa y sin poder entender el concepto de actualización en Mongoose :)

Aquí está el trato:

Tengo un esquema y modelo de contacto (propiedades abreviadas):

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

Recibo una solicitud del cliente que contiene los campos que necesito y uso mi modelo de la siguiente manera:

mongoose.connect(connectionString);
var contact = new Contact({
    phone: request.phone,
    status: request.status
});

Y ahora llegamos al problema:

  1. Si llamo, contact.save(function(err){...})recibiré un error si el contacto con el mismo número de teléfono ya existe (como se esperaba, único)
  2. No puedo llamar update()al contacto, ya que ese método no existe en un documento.
  3. Si llamo a la actualización del modelo:
    Contact.update({phone:request.phone}, contact, {upsert: true}, function(err{...})
    entro en un bucle infinito de algún tipo, ya que la implementación de la actualización de Mongoose claramente no quiere un objeto como segundo parámetro.
  4. Si hago lo mismo, pero en el segundo parámetro paso una matriz asociativa de las propiedades de la solicitud, {status: request.status, phone: request.phone ...}funciona, pero entonces no tengo ninguna referencia al contacto específico y no puedo encontrar sus propiedades createdAty updatedAt.

Entonces, la conclusión, después de todo lo que intenté: dado un documento contact, ¿cómo lo actualizo si existe o lo agrego si no existe?

Gracias por tu tiempo.

Traveling Tech Guy avatar Sep 01 '11 14:09 Traveling Tech Guy
Aceptado

Mongoose ahora admite esto de forma nativa con findOneAndUpdate (llama a MongoDB findAndModify ).

La opción upsert = true crea el objeto si no existe. El valor predeterminado es falso .

var query = {'username': req.user.username};
req.newData.username = req.user.username;

MyModel.findOneAndUpdate(query, req.newData, {upsert: true}, function(err, doc) {
    if (err) return res.send(500, {error: err});
    return res.send('Succesfully saved.');
});

En versiones anteriores, Mongoose no admite estos ganchos con este método:

  • valores predeterminados
  • colocadores
  • validadores
  • software intermedio
Pascalius avatar Jul 12 '2014 09:07 Pascalius

Acabo de pasar 3 horas enteras intentando resolver el mismo problema. Específicamente, quería "reemplazar" todo el documento si existe, o insertarlo en caso contrario. Aquí está la solución:

var contact = new Contact({
  phone: request.phone,
  status: request.status
});

// Convert the Model instance to a simple object using Model's 'toObject' function
// to prevent weirdness like infinite looping...
var upsertData = contact.toObject();

// Delete the _id property, otherwise Mongo will return a "Mod on _id not allowed" error
delete upsertData._id;

// Do the upsert, which works like this: If no Contact document exists with 
// _id = contact.id, then create a new doc using upsertData.
// Otherwise, update the existing doc with upsertData
Contact.update({_id: contact.id}, upsertData, {upsert: true}, function(err{...});

Creé un problema en la página del proyecto Mongoose solicitando que se agregara información sobre esto a los documentos.

clint avatar Oct 21 '2011 21:10 clint

Estabas cerca de

Contact.update({phone:request.phone}, contact, {upsert: true}, function(err){...})

pero su segundo parámetro debería ser un objeto con un operador de modificación, por ejemplo

Contact.update({phone:request.phone}, {$set: { phone: request.phone }}, {upsert: true}, function(err){...})
chrixian avatar Sep 20 '2011 14:09 chrixian

Bueno, esperé bastante y no hubo respuesta. Finalmente abandoné todo el enfoque de actualización/inserción y opté por:

ContactSchema.findOne({phone: request.phone}, function(err, contact) {
    if(!err) {
        if(!contact) {
            contact = new ContactSchema();
            contact.phone = request.phone;
        }
        contact.status = request.status;
        contact.save(function(err) {
            if(!err) {
                console.log("contact " + contact.phone + " created at " + contact.createdAt + " updated at " + contact.updatedAt);
            }
            else {
                console.log("Error: could not save contact " + contact.phone);
            }
        });
    }
});

¿Funciona? Sí. ¿Estoy contento con esto? Probablemente no. 2 llamadas DB en lugar de una.
Con suerte, una futura implementación de Mongoose generaría una Model.upsertfunción.

Traveling Tech Guy avatar Sep 05 '2011 03:09 Traveling Tech Guy