I have 2 models Donation and BankDeposit
Donation has a column sender_id
Bank Deposit has a column donated_by_id
So let say I have:
#donations = Donation.all
#bank_deposits = BankDeposit.all
and these 2 arrays return this values for mentioned columns:
#donations.sender_id = [1,3,6,8,9]
#bank_deposits.donated_by_id = [2,3,7,8]
In this example, assuming ids of donations are 1 to 5, result I want to achieve is selecting rows with id 2 and 4 (as they contain 3 and 8 present on bank_deposits.donated_by_id).
How should I implement the code to achieve this?
If you ONLY need the donations you can change the code and try:
#donations = Donation.where(sender_id: BankDeposit.pluck(:donated_by_id))
If you want to keep both and use all the records just filter using select:
bank_deposit_donated_by_ids = #bank_deposits.map(&:donated_by_id)
matched_donations = #donations.select do |elem|
bank_deposit_donated_by_ids.include?(elem.sender_id)
end
Didn't test the syntax/API, but that's the idea.
Try below code
#donations.sender_id & #bank_deposits.donated_by_id
This will give you output of common element id from the both array after that you can filter it in any sense you like.
Hope it will work for you.
Related
I do the following so I am able to group all LineItem's together by count and display the LineItem by count along with the vendor_name
line_items = LineItem.all
vendor_line_items = line_items.group(:vendor_name).select('COUNT(*) as count', 'vendor_name').order('count desc')
My issue is that I am only able to receive the following params: id: nil, vendor_name: "name_here"
Is there a way to accomplish the same thing but allow all params from the model to be passed?
You can't select the rest of the columns since you have different values for each coulmn inside the group (like... if you have 2 LineItem in the same group, which ID do you expect to have?)
You could apply aggregate functions (like COUNT, MAX, MIN, etc) to other columns on the SELECT to tell the database which columns you want for each column I guess.
Personally, I would first get the groups ordered by count and then do more queries when needed to fetch the actual record for the groups.
counts = LineItem.group(:vendor_name).count
# counts should be something like: {vendor_1: X, vendor_2, Y, vendor_3: Z}
# order the vendors using the count for each vendor
ordered_vendors = counts.keys.sort_by { |ven| counts[ven] }
ordered_vendors.each do |vendor|
# do something with each vendor, fetch LineItems, etc
end
The reason why you only see the count and the vendor name is because that is all you are grouping by. Suppose in the database, you have 5 different Vendor A shown below.
vendor_name | product_name
-----------------------------
Vendor A | test
Vendor A | test2
Vendor A | test3
Vendor A | test4
Vendor A | test5
...
When you run your query, SQL will not know what to display for product_name as the group_by will only show 1 row instead of 5. Have a read about it here.
To achieve this you will need to either to group by the other columns too or use a min/max select to pick a value to display. Here is an example:
vendor_line_items = LineItem.select('COUNT(*) AS count', 'vendor_name', 'MAX(product_name)').group(:vendor_name).order('count DESC')
Now each of those results, you can call the attributes method.
Which will give you the following hash:
vendor_line_items.each do |x|
result = x.attributes
# Here result will be a hash.
# {"count" => 5, "vendor_name" => "Vendor A", "product_name" => "test5"}
end
(Not accepted answer unless a better way is received)
I did:
vendor_line_items = Vendor.joins(:line_items).group(:id).order('COUNT(line_items.id) DESC')
This gives me what I want by ordering the results by vendor.line_items.count and allowing me to get all of the associations to display any param I want.
I assume this way is much slower than what I was previously doing as it fetches all records and then on the front end goes through associations to get more records.
In the original way I was doing this. It is what I want minus an extra parameter that I would want the SUM of. The parameter is a decimal attribute. In the same way I count the LineItem that have the same vendor_name, I want to sum of the LineItem.attribute that share the same vendor_name.
Better Answer:
LineItem.select(:vendor_name, 'sum(line_item_revenue) as line_item_revenue', 'COUNT(*) as count').group(:vendor_name)
This seems to get me what I want with less queries (i believe) --- correct me if I am wrong on the queries.
I am quite confused about your code and your expectation. You are selecting the COUNT but the expected result is id instead of count?
If you want to group by vendor_name and show the count of group_by you can try
line_items.group(:vendor_name).count
I have the current query :
#meals = Meal.where(week_day: 1, vacation_mode: false).order('random()')
Meal has two other attributes: max_daily_orders and today_orders. Both are integers.
I want to perform the same query as mentioned above, but only get meals where today_orders is strictly inferior than max_daily_orders
for example:
if the meal 'Hamburger' has today_orders equal to 6 and
max_daily_orders equal to 6, it shouldn't be taken by the query.
whereas the meal 'Fish and Chips' has today_orders equal to 2 and
max_daily_orders equal to 8 so it should be taken by the query
How can I improve my query so that I can compare both attributes ?
You can just have a string of what would be your query inside the where, i usually use this approach because it makes me feel like im writing plain SQL.
This should work for you:
#meals = Meal.where("week_day = 1
AND vacation_mode = false
AND today_orders < max_daily_orders")
I have a Movie model that has many comments,
I simply want to sort them (Movies) using SQL Inside active record based on the number of associated comments per movie.
How can we achieve a behavior like this in the most efficient way.
I want to do this on the fly without a counter cache column
you can do something like this
#top_ten_movies = Comment.includes(:movie).group(:movie_id).count(:id).sort_by{|k, v| v}.reverse.first(10)
include(:movie) this to prevent n+1 in sql
group(:movie_id) = grouping based on movie for each comment
sort_by{|k,v|v} = this will result an array of array for example [[3,15],[0,10][2,7],...]
for first part [3,15] = meaning movie with id = 3, has 15 comments
you can access array #top_ten_movies[0] = first movie which has top comments
default is ascending, with reverse you will get descending comments
I am building a shopping cart app in rails. CartItems model has a column for quantity of the type integer and a column for cart_price of the type decimal. For each item added to the cart a new row is added to the database
Model name CartItems. The controller retrieves quantity and price successfully. But when multiplying I receive the error message above. Once the multiplication works I want to add the products together to get the subtotal for the cart.
def subtotal
#cart_content = #cart_item.pluck(:quantity,:cart_price)
#subtotal = #cart_content.inject(:*)
end
When I remove .inject(:*) from #subtotal the controller retrieves the correct data.
Example output from view for two products, with quantity and price value present
[[3, #BigDecimal:7fc9a9b2d980,'0.1285E3',18(36)>], [1, # BigDecimal:7fc9a9b2d7c8,'0.115E3',9(27)>]]
I'm not 100% sure but what you probably wanted to achieve is:
#cart_content.sum { |c| c.inject(:*) } - single reduce won't work because it expects a number not an array
You are probably better of adding a column to the model that already contains the value of quantity * cart_price # name it row_total
Then you can easily sum the new column like this:
ModelName.sum(:row_total)
You seem to be trying to multiplying the individual elements, which ruby does not like as they are arrays themselves.
As djaszczurowski suggested, I'd recommend summing over the array after multiplying the elements.
Extending on his answer, I'd suggest to replace the inject with the following, as in (at least for me) it is more descriptive of what (I think) you want to do with the code:
#subtotal = #cart_content.sum { |count, price| count * price }
I'm building a summary of data based on multiple entities - to keep things simple for eg. a list of categories and the number of items present in each category returned as json e.g.
{"report":["Fruit",35]}
#array = []
#active_rec = Category.all
#array = #active_rec.collect{ |u| [u.name, ?how to insert AR query result? }
How can I plug a value along with the name that is the result of another query eg. is it possible to perform a query inline on a current row ?
Thanks!
Made some assumptions about your date model:
Fruit.joins(:category).group('categories.id').select('categories.name, COUNT(fruits.id)')
Or (depending on how you want to handle the case of duplicate category names):
Fruit.joins(:category).group('categories.name').count('fruits.id')
Note the output will be in a different format depending on which of these you choose.