2016-12-21 2 views
1

Извините, что похоже, что это может быть дубликат. Я знаком с несколькими обновлениями в Postgres ... но я не могу показаться, чтобы выяснить путь вокруг этого ...Postgres multi-update с несколькими случаями `where`

У меня есть photos таблицу со следующими столбцами: id (первичный ключ), url , sort_order, и owner_user_id.

Мы хотели бы разрешить нашему интерфейсу разрешить пользователю изменять порядок существующих фотографий в виде коллекции. В этом случае, когда взаимодействие перетаскивания перезаказа завершено, я могу послать POST тела нашего API следующие:

req.body.photos = [{id: 345, order: 1, id: 911, order: 2, ...<etc>}] 

В этом случае я могу развернуться и выполнить следующий запрос в цикле в каждый элемент массива.

photos.forEach(function (item) { 
    db.runQuery('update photos set sort_order=$1 where id=$2 and owner_user_id=$3', [item.order, item.id, currentUserId]) 
}) 

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

Большое спасибо заранее.

+0

примечание, помеченное как обман, потому что это mysql, но ... http://stackoverflow.com/questions/40623132/making-changes-to-multiple-records-based-on-change-of-single-record- с-sql/40624979 # 40624979 – e4c5

ответ

1

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

Моей рекомендацией было бы обернуть все известные обновления в одной транзакции. Это не только более любезно для базы данных (компиляция один раз, выполнение многих, фиксация один раз), но это подход ACID к тому, что, как я считаю, вы пытаетесь сделать. Если по какой-либо причине одно из ваших обновлений не удастся, все они потерпят неудачу. Это не позволяет вам иметь две фотографии с порядком «1».

Я не узнал свой язык, но вот пример того, что это может выглядеть, как в C#:

NpgSqlConnection conn = new NpgSqlConnection(connectionString); 
conn.Open(); 

NpgSqlTransaction trans = conn.BeginTransaction(); 
NpgSqlCommand cmd = new NpqSqlCommand("update photos set sort_order=:SORT where id=:ID", 
    conn, trans); 
cmd.Parameters.Add(new NpgSqlParameter("SORT", DbType.Integer)); 
cmd.Parameters.Add(new NpgSqlParameter("ID", DbType.Integer)); 

foreach (var photo in photos) 
{ 
    cmd.Parameters[0].Value = photo.SortOrder; 
    cmd.Parameters[1].Value = photo.Id; 
    cmd.ExecuteNonQuery(); 
} 

trans.Commit(); 

Я думаю, что в Perl, к примеру, было бы еще проще - выключить DBI AutoCommit и зафиксировать после вставок.

CAVEAT: Конечно, добавить ловушку ошибок - я просто иллюстрировал, как это может выглядеть.

Кроме того, я изменил ваше обновление SQL. Если «Id» является основным ключом, я не думаю, что вам нужно дополнительное предложение owner_user_id=$3, чтобы оно работало.

+0

очень круто. благодаря! Я знаком с «транзакциями», и теперь мне не приходило в голову использовать их для этого сценария. как вопрос в отношении 'owner_user_id' - он существует как превентивная мера безопасности ... гарантируя, что только пользователь authed является тем, кому разрешено сортировать данные идентификаторы. – ded

+0

Отличное разъяснение - так что не нужно указывать, какую строку обновлять, а не предотвращать обновление строки при определенных условиях. Теперь имеет смысл. Какой язык был (я не знаю, очевидно)? – Hambone

+0

Я работаю с модулем 'pg' узла для Postgres. См. Https://github.com/brianc/node-postgres – ded

Смежные вопросы