¿Cómo actualizo/actualizo un documento en Mongoose?
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:
- 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) - No puedo llamar
update()
al contacto, ya que ese método no existe en un documento. - 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. - 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 propiedadescreatedAt
yupdatedAt
.
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.
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
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.
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){...})
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.upsert
función.