Activerecord list distinct WITH count - ruby-on-rails-3

I have a Resource Model with entries that can have the same resource name:
Resource Model
ID name
1 Item 1
2 Item 1
3 Item 2
4 Item 3
....
I would like to list distinct Resource.name with a count of the number of occurances of that resource in my view:
Item 1 (2)
Item 2 (1)
Item 3 (1)
Performance is my main concern since there is a lot already going on in the view since it's a dashboard.
I could probably do this by pulling all of the Resources and filtering in the view but that will be pretty heavy on page load times, does anyone have a better idea?

This can be easily done with the combination of group and count methods:
Item.group(:name).count
>> ["Item 1" => 2, "Item 2" => 1, "Item 3" => 1]

Related

Directus query: must equal the values

I'm trying to call the API of Directus with the following statement:
I want all the items where the category.categories_id (not the ID of the collection categories) equals these values.
So I have a collection Items:
Id
Slug
Short_description
Long_description
Image
Status
Categories
Manufacturer
A table with the many to many relation Items_categories:
Id
Items_id
Categories_id
And a collection Categories:
Id
Name
Status
Imagine I have a item "Car1" with the categories_id 2 and 4 and a item "Car2" with the categories_id 1 and 4. When I filter the values 2 and 4 I only want the item "Car1".
These are the queries that I tried:
<directus>/items/items?filter[categories][categories_id][_in]=2,4&fields=*,categories.*,manufacturer.name,manufacturer.id
And I tried:
<directus>/items/items?filter[categories][categories_id][_eq]=2,4&fields=*,categories.*,manufacturer.name,manufacturer.id
This results in retrieving items that have 2 OR 4 as categories_id, but I want the items that have 2 AND 4.
I also saw the 'all' operator here: https://v8.docs.directus.io/api/query/filter.html, but it didn't returned the expected items.
Can anyone help me? I would really appreciate it!

Database Design: Order Items with quantities spanning multiple statuses

I have a requirement to create a database that holds orders with items for each order.
This would be the traditional table setup
Order Table
Id (pk)
CustomerId (fk)
1
1
Item Table
Id (pk)
OrderId (fk)
StatusId (fk)
Quantity
1
1
1
1000
ItemStatus Table
(Don't worry about how the data knows which status is first, second, third, etc)
Id (pk)
Name
Description
IsStart
IsTerminal
1
New
For newly created items
1
0
2
Materials Ordered
For indicating that raw materials are ordered
0
0
3
Pre-Fabrication
For receiving materials and gathering other resources
0
0
4
In Work
For indicating that the assembly process is underway
0
0
5
Staging
For preparing the items for shipping
0
0
6
Shipped
For indicating that items are complete and no longer in the facility
0
1
However
I have the requirement to take the above quantity of 1000 and break it down by status as it pertains to the business workflow.
My initial implementation looked something like this, but I wanted to reach out and see if there is a better design.
Modified Item Table
Id (pk)
OrderId (fk)
1
1
QuantityBreakdown Table
Id (pk)
OrderItemId (fk)
StatusId (fk)
Quantity
1
1
2
200
2
1
3
200
3
1
4
400
4
1
5
200
Edit
Here are some examples in layman terms to help clarify expected solution. All scenarios will be simplified by only having a single item. Also, the handling of ordering materials is out of scope; I just need to know that the item is waiting.
In these examples, we will be handling the creation process of a burger (item #1). In more advanced scenarios, we could add another ITEM such as fries (that would be item #2)
Example 1
A restaurant order is created with 1 burger. All materials needed for the assembly of the burger are on-hand; therefore, the burger will progress through the statuses with all quantities (New => Prep => Cooking => Packaged => Delivered).
Example 2
A restaurant order is created with 2 burgers. Only enough materials for one burger are on-hand; therefore, the item quantity needs to be split. Since we don't want the customer waiting, the first burger will progress through the statuses with a quantity of 1. While the second burger will have to wait in a new status called Pending. Then once the materials are available, the second burger may continue the workflow.
Well I cannot just comment to ask for clarifications.
But I would have each OrderItem be its on distinct item in an order with its own Status (status in OrderItem). So if in fact you had 4 sets of the same item, each would have its own status.
You could always group-by if you want the total # of each OrderItemId

SQL group related rows in a list

I'm a bit stuck with this...
I have items table:
id | name
1 | item 1
2 | item 2
3 | item 3
4 | item 4
and related items table:
id | item_id | related_item_id
2 | 1 | 2
3 | 1 | 4
so this means that item 1 is related to items 2 and 4.
Now I'm trying to display these in a list where related items follow always the main item they are related to:
item 1
item 2
item 4
item 3
Then I can visually show that these items 2 and 4 are related to item one and draw something like:
item 1
-- item 2
-- item 4
item 3
To be honest, haven't got any ideas myself. I quess I could query for items which are not related to any other item and get a list of "parent items" and then query relations separately in a script loop. This is not definately the sexiest solution...
I am assuming that this question is about ordering the items list, without duplicates. That is, a given item does not have more than one parent (which I ask in a comment).
If so, you can do this with a left outer join and cleverness in the order by.
select coalesce(r.related_item_id, i.id) as item_id
from items i left join
related r
on i.id = r.related_item_id
order by coalesce(r.item_id, i.id),
(r.related_item_id is null) desc;
The left outer join identifies parents because they will not have any rows that match. If so, the coalesce() finds them and uses the item id.
In my opinion , rather than implementing this logic in a query , you should move it to your actual code.
assuming that item_ids are sequential, you can find the largest number of item_id, then in a loop
you can find related_item_id to each item_id and make a convenient data structure out of it.
This functionality comes under the category of hierarchical queries. In Oracle its handled by connect by clause not sure about mysql. But you can search "hierarchical queries mysql" to get the answer.

GridView Blank On Pagination

I have no problem getting a GridView or ListView to page, normally. If I use Sql datasource and I use a query like:
SELECT RecipeName FROM PostedRecipes
and I enter Hot Dog, for example, in a search text box, and there are 40 Hot Dog recipes, the GridView/ListView will show page 1 with 10 recipes (if the count is set to 10) and show that there are 3 more pages to go. Each page then, page 2 or 3 or 4, will show additional recipes. However,
If I use a query like:
SELECT RecipeName FROM PostedRecipes
WHERE RecipeName LIKE '%' + #RecipeName + '%' GROUP BY RecipeName
and I make the same search entry, the GridView will show page 1 with 10 recipes and indicate that there are 3 more pages. BUT, if I click on page 2 or 3 or 4, a blank page is then displayed.
If I set the count to 40, all 40 recipes will be displayed on the initial search - which would indicate that all the recipes are being retrieved from the database. I am not sure if this is some sort of GridView problem or a postback problem of some sort. Any help would be appreciated.

Receive product groups and products with one query

I have two tables:
Product
------------------------------------
id group_id name quick_select
------------------------------------
1 1 product1 1
2 3 product2 0
3 5 product3 1
Product_group
-----------------------
id name parent_id
-----------------------
1 group1 0
2 group2 0
3 group3 1
4 group4 1
5 group5 3
I making a navigation system for quick select products. I show categories to user and user can navigate in them by clicking category button, then goes level down to subcategory and goes down so many levels that finally it can't go deeper - then I show products. First I show root categories where there's products under them and under those root categories subcategories, subsubcategories and so on.
In my query I want select all root categories (where parent_id=0), if there's products in them and in their subcategories and subsubcategories and so on, where quick_select must be 1 in product table. And I don't know the deepness of categories - how many levels there are.
Is it possible with one query? Or do I need to do two queries?
I made so far, with this query:
SELECT pg.id, pg.name, pg.parent_id AS parent_id
FROM product_group AS pg
LEFT JOIN product AS p ON pg.id = p.group_id
WHERE pg.parent_id = 0 AND p.id IS NOT NULL AND p.quick_select = 1
GROUP BY pg.id
But I don't receive root categories which subcategory is empty, which subcategory is empty and under this is one more subcategory with products with quick_select=1.
Sorry for my bad english.
I want to receive all categories where products with quick_select=1 are, not products
-- Category
| |
| product
|
-- Category
|
Category
|
Category
|
multiple products
The bad news is that you can't do this in SQLite, at least with this data structure, since SQLite doesn't support recursive SQL or window functions.
If select performance is important, you can try to organize the data like this:
http://articles.sitepoint.com/article/hierarchical-data-database/2
Another option is to add the root id to each row at input time.
Basically, at some point you will have to use multiple selects and determine the root id at the application level.
Update:
Ok, this is very much pseudo-code, but it should get you there.
You need a language that has some sort of hashmap or named array datatype.
hashmap results, parent, nodes, nodes_new; # variables
foreach (res in sql_execute("SELECT id, parent_id FROM product_group;") ) {
parent[res.id] = res.parent_id;
}
# get groups with products
foreach (res in sql_execute("SELECT pg.id FROM product_group AS pg INNER JOIN
product AS p ON pg.id = p.group_id
WHERE p.quick_select = 1 GROUP BY pg.id ") ) {
nodes[res.id] = res.id;
}
while (length(nodes) > 0) {
foreach (i in nodes) {
if (i = 0) { results[i] = i; } # if its a root node, add to results
else { nodes_new[parent[i]] = parent[i]; } # otherwise, add parent to the next round
}
nodes = nodes_new; # prepare for next round
}
print results;