Pg-promise性能提升:具有多个更新参数的多个插入

正如我在这里和那里所build议的那样,我正在实施Vitaly的pg-promise性能模式。

这是我的代码:

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是一个对象数组,并且库的插入帮助器使用该数组构build插入请求,如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] ); }); 

在这种情况下,当更新被调用时,这些参数引用最初为插入提出的值。

你的任务需要一个静态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); }); 

UPDATE

如果你的静态的排除字段列表太长,你想简化它,你总是可以依赖于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(); 

UPDATE

使用库的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" 

请参阅ColumnSet.assignColumns

不要使用h.sets() 。 只需自己编写conflict_action 。 手册说

ON CONFLICT DO UPDATE中的SET和WHERE子句可以使用表的名称(或别名)访问现有行,并使用特殊排除表访问要插入的行。

Postgres – 插入