Declarating a variable based on hashes - ruby

I have two databases: one is old and deprecated; the other one is new, working. Both of them have a table called brands.
In the deprecated database, the brands table is something like the following:
id | name
1 | Playstation 1
2 | Playstation 2
3 | Playstation 3
4 | Playstation 4
5 | Xbox
6 | Xbox 360
7 | Xbox One
In the new one, this is the brands table:
id | name
1 | Xbox
2 | Xbox 360
3 | Xbox One
4 | Playstation 1
5 | Playstation 2
6 | Playstation 3
7 | Playstation 4
In practice, the scenario is more complex, but the example I gave represents well. So, there's also a products table:
id | name | brand_id | created_at | updated_at
I want to import products from the old database to the new one, but the brands aren't matching by id as you saw. Then, I want to do something like this:
brand_id 1 on old_database == brand_id 4 on new_database
To be more specific, is kind of a dictionary without ifs.
This is what I've done:
if query.brand == 1
brand_id == 4
elsif query.brand == 2
brand_id = 5
end
But this isn't what I really want. Yes, it works, but I want to do something simpler. I think hashes are exactly what I'm looking for. Any suggestions?

You could declare a hash like this:
brand_map = {1 => 4, 2 => 5} # add other entries as needed
and then lookup the new id like this:
brand_id = brand_map[1]
=> 4

Yes, it seems that a hash is what you want. For example,
id_map = { 1=>4, 2=>5, ... } # old id => new id
then for a record id, name, write it to the new database as id_map(id), name.

Related

Eloquent query adding a new field depending on a pivot table

I'm trying to make some query with Eloquent but cannot get the result I really want. Using Laravel 6.
I have the next tables:
Table Users:
id | user
============
1 | Andy
Table Colors:
id | color
============
1 | red
2 | blue
3 | white
4 | green
5 | black
Table user_colors:
id | user_id | color_id
==========================
1 | 1 | 1
1 | 1 | 4
What I want is something to get all the colors, but mark as active the ones in the pivot. Something like this:
id | color | active
====================
1 | red | 1
2 | blue
3 | white
4 | green | 1
5 | black
Any idea?
This should return a collection of Color objects with the one's associated with the given user given a property of active set to true
$user_colors = User::find(1)->colors;
$colors = Colors::all()->transform(function ($color) use ($user_colors) {
if ($user_colors->contain($color)) {
$color->active = true;
}
return $color;
});
Whilst this should achieve the result you need, without knowing the context in which you want to use it, it may be inefficient.
There are several ways to achieve this task. One of them could be to use appends in models.
Appends are attributes that you can dynamically add to your model class.
E.g. you can edit your Color model like this:
class Color extends Model {
// Your code...
protected $appends = ['active'];
public function getActiveAttribute() {
$is_active = UserColor::whereColorId($this->id)->first();
if (!is_null($is_active)) return true; // Or 1, up to you
return false; // Or 0, up to you
}
}
If you use this method, you can access to $color->active attribute.
Note that this is only one of the different methods that you can use to do this task.
Reference: Laravel Appends Documentation

pivot table with multiple columns in Eloquent

Here's my scenario:
I have a Event model and a Stage model, a event can have multiple stages and a stage could be assigned to multiple events. So Many-to-many. The thing is, a stage has a sort_order, and that sort_order could be different in each event. That's why I added the sort_order into the pivot table instead in, for example, the stage table.
table: events_stages
| event_id | stage_id | sort_order |
------------------------------------
| 1 | 1 | 1 |
| 1 | 2 | 2 |
| 1 | 5 | 3 |
The thing is when I'm going to relate the Stage with the events its in,
I'm doing something like in the StageController:
sending a post with events: [1,2,3] and sort_order: [1,1,2]
$relatedEvents = array();
foreach ($request->events as $key => $event)
{
$relatedEvents[] = array(
'event_id' => $relatedEventId,
'sort_order' => $request->sort_order[$key]
);
}
$stage->events()->sync(
$relatedEvents
);
but rely simply in the order of the post, doesn't seem like a really good idea.
Does anyone have a nicer solution?
Thanks!
Sometimes is better to create another model (and use it as a pivot) rather than use pivot table itself. You have more control. I'm not sure what exactly you want to achieve.

Insert array on multiple rows

I have a multiple select:
Form::select('color', array('1' => 'Red', '2' => 'Blue', '3' => 'Green', ... ), null, array('multiple'));
How can I insert these values into a table on separate rows, like this:
id | user_id | color
----------------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 1 | 4
5 | 2 | 1
6 | 2 | 3
In the above example, user with an id of 1 selected 4 different values in the select and each was inserted on a separate row.
I have this working in this way:
foreach (Input::get('tags') as $key => $value)
{
$user_color = new UserColor;
$user_color->user_id = $user->id;
$user_color->color = $key;
$user_color->save();
}
Is there a better way of doing this? It seems odd using a foreach loop when it feels like Laravel should have some sort of built-in method of inserting multiple values on multiple rows.
As Laravel doc provided,
You may also use the sync method to attach related models. The sync
method accepts an array of IDs to place on the pivot table. After this
operation is complete, only the IDs in the array will be on the
intermediate table for the model:
In this case,
$colors = Input::get('tags');
$user->colors()->sync($colors);
Please make sure to set relation in your User model :
public function colors()
{
return $this->belongsToMany('Color');
}
You can also use attach method when you parameter is not array. To more clear, Here is difference between attach and sync.

Bulk Update in 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.
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!
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!

Bitwise operations in Postgres

I have the following tables:
types | id | name
------+----+----------
1 | A
2 | B
4 | C
8 | D
16| E
32| F
and
vendors | id | name | type
--------+----+----------+-----
1 | Alex | 2 //type B only
2 | Bob | 5 //A,C
3 | Cheryl | 32 //F
4 | David | 43 //F,D,A,B
5 | Ed | 15 //A,B,C,D
6 | Felix | 8 //D
7 | Gopal | 4 //C
8 | Herry | 9 //A,D
9 | Iris | 7 //A,B,C
10| Jack | 23 //A,B,C,E
I would like to query now:
select id, name from vendors where type & 16 >0 //should return Jack as he is type E
select id, name from vendors where type & 7 >0 //should return Ed, Iris, Jack
select id, name from vendors where type & 8 >0 //should return David, Ed, Felix, Herry
What is the best possible index for tables types and vendors in postgres? I may have millions of rows in vendors. Moreover, what are the tradeoffs of using this bitwise method compared with Many To Many relation using a 3rd table? Which is better?
Use can use partial indices to work around the fact that "&" isn't an indexable operator (afaik):
CREATE INDEX vendors_typeA ON vendors(id) WHERE (type & 2) > 0;
CREATE INDEX vendors_typeB ON vendors(id) WHERE (type & 4) > 0;
Of course, you'll need to add a new index every time you add a new type. Which is one of the reasons for expanding the data into an association table which can then be indexed properly. You can always write triggers to maintain a bitmask table additionally, but use the many-to-many table to actually maintain the data normally, as it will be much clearer.
If your entire evaluation of scaling and performance is to say "I may have millions of rows", you haven't done enough to start going for this sort of optimisation. Create a properly-structured clear model first, optimise it later on the basis of real statistics about how it performs.

Resources