mysql - tabla - select recursivo
Crear o actualizar secuela (8)
Estoy usando Sequelize en mi proyecto Nodejs y encontré un problema que me cuesta mucho resolver. Básicamente tengo un cron que obtiene una matriz de objetos de un servidor que lo inserta en mi base de datos como un objeto (en este caso, dibujos animados). Pero si ya tengo uno de los objetos, tengo que actualizarlo.
Básicamente tengo una matriz de objetos y podría usar el método BulkCreate (). Pero cuando el Cron comienza de nuevo, no lo resuelve, por lo que necesitaba algún tipo de actualización con una marca de verdad superior. Y el problema principal: debo tener una devolución de llamada que se active solo una vez después de todas estas creaciones o actualizaciones. ¿Alguien tiene una idea de cómo puedo hacer eso? Iterar sobre un conjunto de objetos ... ¿crearlo o actualizarlo y luego obtener una única devolución de llamada después?
Gracias por la atención
Aquí hay un ejemplo simple que actualiza deviceID -> pushToken map o lo crea:
var Promise = require(''promise'');
var PushToken = require("../models").PushToken;
var createOrUpdatePushToken = function (deviceID, pushToken) {
return new Promise(function (fulfill, reject) {
PushToken
.findOrCreate({
where: {
deviceID: deviceID
}, defaults: {
pushToken: pushToken
}
})
.spread(function (foundOrCreatedPushToken, created) {
if (created) {
fulfill(foundOrCreatedPushToken);
} else {
foundOrCreatedPushToken
.update({
pushToken: pushToken
})
.then(function (updatedPushToken) {
fulfill(updatedPushToken);
})
.catch(function (err) {
reject(err);
});
}
});
});
};
El sonido le gusta que desea envolver sus llamadas Sequelize dentro de un async.each .
Esta podría ser una vieja pregunta, pero esto es lo que hice:
var updateOrCreate = function (model, where, newItem, onCreate, onUpdate, onError) {
// First try to find the record
model.findOne({where: where}).then(function (foundItem) {
if (!foundItem) {
// Item not found, create a new one
model.create(newItem)
.then(onCreate)
.catch(onError);
} else {
// Found an item, update it
model.update(newItem, {where: where})
.then(onUpdate)
.catch(onError);
;
}
}).catch(onError);
}
updateOrCreate(
models.NewsItem, {title: ''sometitle1''}, {title: ''sometitle''},
function () {
console.log(''created'');
},
function () {
console.log(''updated'');
},
console.log);
Esto se puede hacer con el emisor de eventos personalizado.
Suponiendo que sus datos están en una variable llamada datos.
new Sequelize.Utils.CustomEventEmitter(function(emitter) {
if(data.id){
Model.update(data, {id: data.id })
.success(function(){
emitter.emit(''success'', data.id );
}).error(function(error){
emitter.emit(''error'', error );
});
} else {
Model.build(data).save().success(function(d){
emitter.emit(''success'', d.id );
}).error(function(error){
emitter.emit(''error'', error );
});
}
}).success(function(data_id){
// Your callback stuff here
}).error(function(error){
// error stuff here
}).run(); // kick off the queries
Me gustó la idea de Ataik, pero la acorté un poco:
function updateOrCreate (model, where, newItem) {
// First try to find the record
return model
.findOne({where: where})
.then(function (foundItem) {
if (!foundItem) {
// Item not found, create a new one
return model
.create(newItem)
.then(function (item) { return {item: item, created: true}; })
}
// Found an item, update it
return model
.update(newItem, {where: where})
.then(function (item) { return {item: item, created: false} }) ;
}
}
Uso:
updateOrCreate(models.NewsItem, {slug: ''sometitle1''}, {title: ''Hello World''})
.then(function(result) {
result.item; // the model
result.created; // bool, if a new item was created.
});
Opcional: agregue el manejo de errores aquí, pero recomiendo encarecidamente encadenar todas las promesas de una solicitud y tener un controlador de errores al final.
updateOrCreate(models.NewsItem, {slug: ''sometitle1''}, {title: ''Hello World''})
.then(..)
.catch(function(err){});
Puedes usar upsert Es mucho más fácil.
Detalles de implementacion:
MySQL : implementado como una sola consulta INSERTE valores EN UNA CLAVE DUPLICADA
Valores de UPDATE PostgreSQL - Implementado como una función temporal con manejo de excepciones: INSERTAR EXCEPCIÓN CUANDO unique_constraint UPDATE
SQLite - Implementado como dos consultas INSERT; ACTUALIZAR. Esto significa que la actualización se ejecuta independientemente de si la fila ya existía o no
puede usar findOrCreate
y luego update
métodos en secuenciación. Aquí hay una muestra con async.js
async.auto({
getInstance : function(cb) {
Model.findOrCreate({
attribute : value,
...
}).complete(function(err, result) {
if (err) {
cb(null, false);
} else {
cb(null, result);
}
});
},
updateInstance : [''getInstance'', function(cb, result) {
if (!result || !result.getInstance) {
cb(null, false);
} else {
result.getInstance.updateAttributes({
attribute : value,
...
}, [''attribute'', ...]).complete(function(err, result) {
if (err) {
cb(null, false);
} else {
cb(null, result);
}
});
}
}]
}, function(err, allResults) {
if (err || !allResults || !allResults.updateInstance) {
// job not done
} else {
// job done
});
});
Desde los docs , no necesita consultar where
realizar la actualización una vez que tenga el objeto. Además, el uso de la promesa debería simplificar las devoluciones de llamada:
Implementación
function upsert(values, condition) {
return Model
.findOne({ where: condition })
.then(function(obj) {
if(obj) { // update
return obj.update(values);
}
else { // insert
return Model.create(values);
}
}
})
}
Uso
upsert({ first_name: ''Taku'' }, { id: 1234 }).then(function(result){
res.status(200).send({success: true});
});
Nota
- Esta operación no es atómica.
- crea 2 llamadas de red
lo que significa que es recomendable repensar el enfoque y, probablemente, solo actualizar los valores en una llamada de red y:
- mira el valor devuelto (es decir, row_affected) y decide qué hacer
- devolver un éxito si la operación de actualización tiene éxito. Esto se debe a que si el recurso existe no está dentro de la responsabilidad de este servicio.