Upsert в Postgres с помощью node.js - PullRequest
       24

Upsert в Postgres с помощью node.js

4 голосов
/ 27 октября 2011

Я пытаюсь выполнить вставку или обновление в базе данных postgres, используя node.js с расширением pg (версия 0.5.4).

Пока у меня есть этот код: (...)

client.query({
            text: "update users set is_active = 0, ip = $1 where id=$2",
            values: [ip,id]
        }, function(u_err, u_result){
            debug(socket_id,"update query result: ",u_result);
                debug(socket_id,"update query error: ",u_err);

                    date_now = new Date();
            var month = date_now.getMonth() + 1;

            if(!u_err){

                client.query({
                    text: 'insert into users (id,first_name,last_name,is_active,ip,date_joined) values' +
                    '($1,$2,$3,$4,$5,$6)',
                    values: [
                            result.id, 
                            result.first_name,
                            result.last_name,
                            1,
                            ip,
                            date_now.getFullYear() + "-" + month + "-" + date_now.getDate() + " " + date_now.getHours() + ":" + date_now.getMinutes() + ":" + date_now.getSeconds()
                            ]
                }, function(i_err, i_result){
                    debug(socket_id,"insert query result: ",i_result);
                    debug(socket_id,"insert query error: ",i_err);
                });
            }
        });

Проблема в том, что, хотя оба запроса работают, проблема всегда в том, чтобы выполнять оба, а не только запуск функции вставки в случае сбоя обновления.

Функции отладки в выводе кода примерно такие:

UPDATE

Object { type="update query result: ", debug_value={...}}
home (linha 56)
Object { type="update query error: ", debug_value=null}
home (linha 56)
Object { type="insert query result: "}
home (linha 56)
Object { type="insert query error: ", debug_value={...}}

Вставить

Object { type="update query result: ", debug_value={...}}
home (linha 56)
Object { type="update query error: ", debug_value=null}
home (linha 56)
Object { type="insert query result: ", debug_value={...}}
home (linha 56)
Object { type="insert query error: ", debug_value=null}

** РЕДАКТИРОВАТЬ **

ОТВЕТ ОТ разработчика node-postgres:

Возможно получить количество строк, затронутых вставкой, и Обновить. Это не полностью реализовано в родных привязках, но делает работать в чистой версии JavaScript. Я буду работать над этим в рамках на следующей неделе или две. В то же время использовать чистую версию JavaScript и посмотрите здесь:

https://github.com/brianc/node-postgres/blob/master/test/integration/client/result-metadata-tests.js

** END EDIT **

Может кто-нибудь помочь?

Ответы [ 2 ]

2 голосов
/ 28 апреля 2012

У меня была эта проблема при подключении к экземпляру PG с использованием JDBC. Решение, которое я в итоге использовал, было:

UPDATE table SET field='C', field2='Z' WHERE id=3;
INSERT INTO table (id, field, field2)
       SELECT 3, 'C', 'Z'
       WHERE NOT EXISTS (SELECT 1 FROM table WHERE id=3);

Обновление ничего не делает, если запись не существует, а вставка ничего не делает, если запись существует. Он работает довольно хорошо и является решением на основе SQL по сравнению с хранимой процедурой.

Вот начальный вопрос: Вставить, при повторном обновлении в PostgreSQL?

2 голосов
/ 03 ноября 2011

Непосредственный ответ на ваш вопрос - использовать хранимую процедуру для выполнения upsert.

http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE

Что-то вроде этого отлично работает с модулем pg.

client.query({
  text: "SELECT upsert($1, $2, $3, $4, $5, $6)"
  values: [ obj.id, 
            obj.first_name,
            obj.last_name,
            1,
            ip,
            date_now.getFullYear() + "-" + month + "-" + date_now.getDate() + " " + date_now.getHours() + ":" + date_now.getMinutes() + ":" + date_now.getSeconds()
          ]
}, function(u_err, u_result){
  if(err) // this is a real error, handle it

  // otherwise your data is updated or inserted properly
});

Конечно, это предполагает, что вы используете какой-то объект модели, который имеет все необходимые вам значения, даже если они не меняются.Вы должны передать их всех в упор.Если вы застряли, делая это так, как вы показали здесь, вам, вероятно, следует проверить фактический объект ошибки после обновления, чтобы определить, произошел ли сбой, потому что строка уже существует, или по какой-то другой причине (которая является настоящей ошибкой БД, котораянеобходимо обработать).

Тогда вы должны разобраться с потенциальным состоянием гонки между моментом, когда ваше обновление не удалось, и временем, когда вставка прошла.Если какая-то другая функция пытается вставить с тем же идентификатором, у вас есть проблема.Транзакции хороши для этого.Это все, что я получил прямо сейчас.Надеюсь, это поможет.

...