Question

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.

Was it helpful?

Solution

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!

OTHER TIPS

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!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top