Sorry for bad English ))
I have an array of ids in my ruby code.
Example:
[[10], [], [10, 1, 3], []]
Can I load User model from MySQL table users in one query by saving grouping?
Example:
[[#<User id=10>], [], [#<User id=10>, #<User id=1>, #<User id=3>], []]
Environment: Ruby 2.5.1 | Rails 5 | MySQL
One of found solution:
I can flat my array of ids and load my model by that array into hash:
hash = User.where(id: array.flatten).index_by(&:id)
Then, during iterating, through array I can load my objects from hash in the right order like that:
array.each do |ids|
users = ids.map { |id| hash[id] }
# do smth
end
This is simple: use flatten method for array:
ids = [[123], [], [123, 1, 3, 4], [70, 80]]
user_ids = ids.flatten.reject(&:blank?).uniq
users = User.where(id: user_ids)
edited:
not optimal (recursive) method for your need:
def map_users_by_id(ids_array:, users:)
result = []
ids_array.each do |array_element|
if (array_element).is_a? Array
result << map_users_by_id(ids_array: array_element, users: users)
else
result << users[array_element]
end
end
return result
end
ids = [[123], [], [123, 1, 3, 4], [70, 80]]
user_ids = ids.flatten.reject(&:blank?).uniq
users = Hash[User.where(id: user_ids).map{|user|[user.id, user]}]
result = map_users_by_id(ids_array: ids, users: users)
Related
Suppose that I have a MySQL table with a JSON field that contains only numbers, like this (note: using MySQL 8):
CREATE TABLE my_table (
id int,
some_field json
);
Sample data:
id: 1
some_field: [1, 2, 3, 4, 5]
id: 2
some_field: [3, 6, 7]
id: 3
some_field: null
I would like to merge another array of data with the existing values of some_field, while removing duplicates. I was hoping that this might work, but it didn't:
update my_table set some_field = JSON_MERGE([1, 2, 3], some_field)
The result of this would be:
id: 1
some_field: [1, 2, 3, 4, 5]
id: 2
some_field: [1, 2, 3, 6, 7]
id: 3
some_field: [1, 2, 3]
Considering you have 3 records in your table and you want to merge 1 and 2 as mentioned in your example.
I hope JavaScript is suitable to follow through for you.
// Get both the records
const records = db.execute(“SELECT id, some_field FROM my_table WHERE id=1 OR id=2”);
// You get both the rows.
// Merging row1, you can either use the Set data structure if you’re dealing with numbers like your example, or you could loop using a map and use the spread operator if using JSON. Since your object is an array, I’ll just be explaining to merge 2 arrays.
records[0].some_field = Array.from(new Set(records[0].some_field + record[1].some_field))
// Same for second record.
records[1].some_field = Array.from(new Set(records[0].some_field + record[1].some_field))
// Now update both the records in the database one by one.
i have array like this: [1, 1, 1, 2, 3]. How i can get users with a duplicate? For example this query return list without duplicate
list= User.objects.filter(id__in=[1, 1, 1, 2, 3])
for example it will be users with id's:
1,
2,
3
but i need list of users like this:
1,
1,
1,
2,
3
list = []
for x in [1, 1, 1, 2, 3]:
list.append(User.objects.filter(id=x)
It this what you mean? I don't quite understand the spacing.
Get your queryset sorted in the right order. .order_by('id) for ascending by id (which may be the default anyway). Then iterate over the queryset with code to make extra operations with the same object (or a copy thereof) as dictated by the list of IDs.
idlist = [1, 1, 1, 2, 3]
queryset = User.objects.filter(id__in = idlist ).order_by('id')
for object in queryset:
for _ in range( idlist.count( object.id))
do_something_with( object)
Note, this is only one DB call (one queryset), unlike the accepted answer which does one DB query for each element in the id list. Not good.
I have two tables users and location. I need to join both tables
what i need is get all the area number of all the users which are present in the user table.
ie user 1 has 3 entries in the second table so i need to join the table in such a way that is,
id1 = 1
area = 2,3
area 2 is repeating so do not include it twice
i tried the join but now getting the correct way to doing it.
What i tried?
$location = User::
join('addresses','users.id1','=','addresses.id1') ->select('users.id1','addresses.area')
->get();
Expected Output
User 1 -> area ->2,3
Here are the two ways to do this.
Firstly you can use Laravel relationship:-
In your model User create relationship:-
function addresses()
{
return $this->hasMany(Address::class, 'id1', 'id1');
}
Now in your User controller you can get User addresses (areas) like this
$users = User::with('addresses')->get();
dd($users->toArray());
This will print something like this
[
{
id1: 1,
name: abaa
pwd: 12345
addresses: [
{
id2: 1,
id1: 1,
area: 2
},
{
id2: 2,
id1: 1,
area: 3
},
{
id2: 3,
id1: 1,
area: 3
}
]
},
{
...
}
]
Second you can use Laravel relationship:-
$builder = new User;
$builder->join('addresses','users.id1','=','addresses.id1')
->selectRaw("users.*, GROUP_CONCAT(DISTINCT addresses.area SEPARATOR ',') as distinct_areas")
->groupBy("users.id1")
->get();
This query will give you result something like this
[
{
id1: 1,
name: abaa,
pwd: 12345,
distinct_areas: 2,3
},
{
...
}
]
I think this will help you.
I have a table Followership, in which every record has attributes user_id and follower_id.
I can do something like this:
Followership.limit(10).pluck('user_id, follower_id)
But this will give me result like this [[1,A][2,B],[3,C],[4,A],[1,B][2,D]]
I want to convert the above array in such a way that all arrays with same user_ids should be merged in following form [user_id, FOLLOWER_ID(S)]
i.e;
[[1,[A,B]][2,[B,D]],[3,C],[4,A]]
Here user_id = 1 has two followers A,B and user_id = 2 has two followers B,D
How to do this?
As pointed out by Sergio, you could use group_by with the array that you get after pluck, for example:
arr = [[1,'A'],[2,'B'],[3,'C'],[4,'A'],[1,'B'],[2,'D']]
a.group_by(&:first).map { |k, v| [k, v.map(&:last)] }
#=> [[1, ["A", "B"]], [2, ["B", "D"]], [3, ["C"]], [4, ["A"]]]
Another approach
a = [[1,'A'],[2,'B'],[3,'C'],[4,'A'],[1,'B'][2,'D']]
h = Hash.new { |h, k| h[k] = [] }
a.inject(h) { |sum, t| sum[t[0]] << t[1]; sum}.to_a
# engine.rb
has_many :pistons
#piston.rb
belongs_to :engine
Piston has a column, piston_count and, of course, engine_id
My database has the following 7 records
Engine.all
#=> [#<Engine id: 1>, #<Engine id: 2>, #<Engine id: 3>]
Piston.all
#=> [#<Piston id: 1, engine_id: 1, piston_count: 1>, #<Piston id: 2, engine_id: 1, piston_count: 2>, #<Piston id: 2, engine_id: 2, piston_count: 1>, #<Piston id: 2, engine_id: 3, piston_count: 2>]
I want to write a query that says, return the Engine containing Pistons with a piston_count of 1 and also contains a piston_count of 2
I've tried...
engines = Engine.joins(:pistons).merge(Piston.where(piston_count: 1))
#=> [#, #]
engines.joins(:pistons).merge(Piston.where(piston_count:2))
#=> []
It returns an empty array because active record turns that into one AND clause. However, if I do an OR statement, it will return too many records. Any thoughts?
Figured it out. This takes the intersect of both Active Record Queries.
engine_ids = Engine.joins(:pistons).merge(Piston.where(piston_count: 1)).pluck(:id) & Engine.joins(:pistons).merge(Piston.where(piston_count: 2)).pluck(:id)
Then go back and retrieve all the intersects.
Engine.where(id: engine_ids)