Повышение производительности Pg-обещания: несколько вставок с несколькими параметрами обновления

Я реализую шаблоны производительности pg-обещания Виталия, как советовано здесь и там.

Вот мой код:

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 является массивом объектов, а вспомогательный модуль библиотеки создает запрос на вставку с использованием этого массива, как указано в pg-обещании 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, параметры ссылаются на значения, изначально предложенные для вставки.

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"

Смотрите ColumnSet.assignColumns

Не использовать h.sets(), Просто напишите conflict_action сам. Руководство говорит

Предложения SET и WHERE в ON CONFLICT DO UPDATE имеют доступ к существующей строке, используя имя таблицы (или псевдоним), и к строкам, предлагаемым для вставки, используя специальную исключенную таблицу.

Postgres - Вставка

Другие вопросы по тегам