Pg-promise 性能提升:具有多个更新参数的多个插入
Pg-promise performance boost : Multiple inserts with multiple update parameters
我正在按照建议实施 Vitaly 的 pg-promise 性能模式 here and 。
这是我的代码:
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 builds an insert request using that Array, as specified in 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 (,,)" +
" ON CONFLICT ON CONSTRAINT application_average_ranking_application_id_country_id_colle_key" +
" DO UPDATE SET country_id=,collection_id=",
[entry.application_id,entry.country_id,collectionId]
);
});
在这种情况下,当调用 Update 时,参数指的是最初建议插入的值。
不要使用 h.sets()
。只需自己编写 conflict_action
即可。手册说
The SET and WHERE clauses in ON CONFLICT DO UPDATE have access to the existing row using the table's name (or an alias), and to rows proposed for insertion using the special excluded table.
您的任务需要一个静态 SQL 来实现这种逻辑,方法是使用 EXCLUDED
作为 table 引用,并排除因冲突而导致的行:
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"
我正在按照建议实施 Vitaly 的 pg-promise 性能模式 here and
这是我的代码:
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 builds an insert request using that Array, as specified in 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 (,,)" +
" ON CONFLICT ON CONSTRAINT application_average_ranking_application_id_country_id_colle_key" +
" DO UPDATE SET country_id=,collection_id=",
[entry.application_id,entry.country_id,collectionId]
);
});
在这种情况下,当调用 Update 时,参数指的是最初建议插入的值。
不要使用 h.sets()
。只需自己编写 conflict_action
即可。手册说
The SET and WHERE clauses in ON CONFLICT DO UPDATE have access to the existing row using the table's name (or an alias), and to rows proposed for insertion using the special excluded table.
您的任务需要一个静态 SQL 来实现这种逻辑,方法是使用 EXCLUDED
作为 table 引用,并排除因冲突而导致的行:
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"