Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bulk Update in RethinkDB

Tags:

rethinkdb

I'm trying to update multiple documents in RethinkDB, based on some precalculated values in a Hash. i.e.

Given a table stats with primary key slug with data like

[{slug: 'foo', stats: {}}, {slug:'bar', stats:{}}]

and given a Hash with values like

updated_stats = {
  'foo' => {a: 1, b: 2}, 
  'bar' => {a: 3, b: 4}
}

I can do this

updated_stats.each{|k,v| 
  r.table('stats').get(k).update{|s| 
    { :stats => v } 
  }  
}

So, why can't I do the following?

r.table('stats').get_all(*updated_stats.keys).update{|s| 
  { :stats => updated_stats[s["slug"]] }  
}

the rql shows nil as the value of updated_stats[s["slug"]]. Would really appreciate any help on this. Thanks.

like image 788
svs Avatar asked Jan 31 '14 19:01

svs


2 Answers

It's a tricky problem.

Here's the solution first.

r.table('stats').get_all(*updated_stats.keys).update{|s| 
  { :stats => r.expr(updated_stats).get_field(s["slug"]) } 
}.run()

Then updated_stats is a ruby hash so when you use the brackets, it's the usual bracket operator, and since updated_stats doesn't have the key s["slug"], it returns nil. So you have to wrap updated_stats in r.expr().

Then brackets in ruby are used for nth, get_field, slice etc. And when given a variable, it cannot guess which one it should use. So you have to explicitly say you want to use get_field. We will add a bracket term, which should fix this problem -- see https://github.com/rethinkdb/rethinkdb/issues/1179

Sorry you ran into this!

like image 76
neumino Avatar answered Jan 04 '23 04:01

neumino


For anyone looking for how to bulk update records, it's actually pretty easy but not at all intuitive.

You actually have to perform an insert while specifying that if there's any conflicts, to update those records. You will obviously need to provide the Id of each record to be updated.

Using the following data set:

|-------------|--------------|
|      id     |     title    |
|-------------|--------------|
|      1      |      fun     |
|-------------|--------------|
|      2      |      in      |
|-------------|--------------|
|      3      |      the     |
|-------------|--------------|
|      4      |      sun     |
|-------------|--------------|

Here's an example (javascript):

const new_data = [
    {id: 1, title: 'dancing'},
    {id: 4, title: 'rain'},
];

r.db('your_db').table('your_table').insert(new_data, {conflict: 'update'});

The results would be:

|-------------|--------------|
|      id     |     title    |
|-------------|--------------|
|      1      |    dancing   |
|-------------|--------------|
|      2      |      in      |
|-------------|--------------|
|      3      |      the     |
|-------------|--------------|
|      4      |      rain    |
|-------------|--------------|

One caveat you should be aware of, though, is that if you represent something in the new_data array that doesn't currently exist in the table, it will be added/upserted.

Cheers!

like image 31
KyleFarris Avatar answered Jan 04 '23 06:01

KyleFarris