Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update or insert on Sequel dataset?

I just started using Sequel in a really small Sinatra app. Since I've got only one DB table, I don't need to use models.

I want to update a record if it exists or insert a new record if it does not. I came up with the following solution:

  rec = $nums.where(:number => n, :type => t)
  if $nums.select(1).where(rec.exists)
    rec.update(:counter => :counter + 1)
  else
    $nums.insert(:number => n, :counter => 1, :type => t)
  end

Where $nums is DB[:numbers] dataset.

I believe that this way isn't the most elegant implementation of "update or insert" behavior.

How should it be done?

like image 357
nooga Avatar asked Mar 19 '12 11:03

nooga


4 Answers

You should probably not check before updating/inserting; because:

  1. This is an extra db call.
  2. This could introduce a race condition.

What you should do instead is to test the return value of update:

rec = $nums.where(:number => n, :type => t)
if 1 != rec.update(:counter => :counter + 1)
  $nums.insert(:number => n, :counter => 1, :type => t)
end
like image 73
radiospiel Avatar answered Nov 13 '22 09:11

radiospiel


Sequel 4.25.0 (released July 31st, 2015) added insert_conflict for Postgres v9.5+
Sequel 4.30.0 (released January 4th, 2016) added insert_conflict for SQLite

This can be used to either insert or update a row, like so:

DB[:table_name].insert_conflict(:update).insert( number:n, type:t, counter:c )
like image 28
Phrogz Avatar answered Nov 13 '22 08:11

Phrogz


I believe you can't have it much cleaner than that (although some databases have specific upsert syntax, which might be supported by Sequel). You can just wrap what you have in a separate method and pretend that it doesn't exist. :)

Just couple suggestions:

  • Enclose everything within a transaction.
  • Create unique index on (number, type) fields.
  • Don't use global variables.
like image 3
Mladen Jablanović Avatar answered Nov 13 '22 08:11

Mladen Jablanović


You could use upsert, except it doesn't currently work for updating counters. Hopefully a future version will - ideas welcome!

like image 1
Seamus Abshere Avatar answered Nov 13 '22 08:11

Seamus Abshere