我正在实施Vitaly的pg-promise性能模式,建议here和there。
这是我的代码:
for (var i=0;i<chunkedData.length;i++){
var insertData = chunkedData[i].map(function (d) {
return {
application_id: d.application_id,
country_id: d.country_id,
collection_id: collectionId
};
});
// Would need to make a loop here, and thus turning the result into an array
var updateData = {
application_id: chunkedData[i][j].application_id,
country_id: chunkedData[i][j].country_id,
collection_id: collectionId
};
var query = h.insert(insertData, cs) +
" ON CONFLICT ON CONSTRAINT application_average_ranking_application_id_country_id_colle_key DO UPDATE SET " +
h.sets(updateData, cs);
db.none(query)
.then(data => {
console.log('success');
})
.catch(error=> {
console.log('insert error : ' + error);
});
}
我的问题是insertData是一个对象数组,而库insert helper使用该数组构建一个插入请求,如pg-promise API中所述。而updateData必须是一个简单的对象。
我希望在以下时间:
ON CONFLICT ON CONSTRAINT constraintName DO UPDATE
触发,更新值与'insertData'数组中的相应对象匹配。
我如何解决这个问题?
我试图把所有东西放在一个循环中,但它会像疯了一样泄漏内存,好吧,我失去了模式的好处......
编辑:
我希望我的查询相当于:
var inserts = data.map(entry => {
return t.none(" INSERT INTO application_average_ranking (application_id,country_id,collection_id) VALUES ($1,$2,$3)" +
" ON CONFLICT ON CONSTRAINT application_average_ranking_application_id_country_id_colle_key" +
" DO UPDATE SET country_id=$2,collection_id=$3",
[entry.application_id,entry.country_id,collectionId]
);
});
在调用Update时,参数引用最初建议插入的值。
答案 0 :(得分:2)
您的任务需要一个静态SQL来实现这种逻辑,方法是使用EXCLUDED
作为表引用,其行由于冲突而排除:
var sqlConflict = " ON CONFLICT ON CONSTRAINT" +
" application_average_ranking_application_id_country_id_colle_key" +
" DO UPDATE SET application_id = excluded.application_id" +
" country_id = excluded.country_id, collection_id = excluded.collection_id";
var insertData = chunkedData.map(function (d) {
return {
application_id: d.application_id,
country_id: d.country_id,
collection_id: collectionId
};
});
var query = h.insert(insertData, cs) + sqlConflict;
db.none(query)
.then(data => {
console.log('success');
})
.catch(error=> {
console.log('insert error : ' + error);
});
<强>更新强>
如果排除字段的静态列表太长并且您想要简化它,您可以始终依赖helpers方法的灵活性:
// or pull them from an object using `Object.keys(obj)`:
var cols = ['application_id', 'country_id', 'collection_id'];
var sets = pgp.helpers.sets({}, cols.map(c=> ({
name: c, mod: '^', def: 'excluded.' + pgp.as.name(c)
})));
console.log(sets);
//=> "application_id"=excluded."application_id","country_id"=excluded."country_id",
// "collection_id"=excluded."collection_id"
// or its simple JavaScript equivalent:
var sets = cols.map(c=> {
var name = pgp.as.name(c);
return name + '=excluded.' + name;
}).join();
<强>更新强>
对于库的7.3.0及更高版本,您应该使用方法assignColumns来生成所有排除的集合,如下所示:
cs.assignColumns({from: 'EXCLUDED'})
//=> "application_id"=EXCLUDED."application_id","country_id"=EXCLUDED."country_id","collection_id"=EXCLUDED."collection_id"
或者,如果您想跳过application_id
,则可以执行以下操作:
cs.assignColumns({from: 'EXCLUDED', skip: 'application_id'})
//=> "country_id"=EXCLUDED."country_id","collection_id"=EXCLUDED."collection_id"
答案 1 :(得分:1)
请勿使用h.sets()
。只需自己写conflict_action
即可。手册说
ON CONFLICT DO UPDATE中的SET和WHERE子句可以使用表的名称(或别名)访问现有行,并使用特殊排除表访问建议插入的行。