How to get unique product list? - ruby-on-rails

We have list of category products having duplicate names.
How to get a list of products which should not have duplicate product name in Postgres?
We are searching for min product ids with group by name.
then searching the products in ids.
category = Category.first
ids = Product.select("MIN(id) as id").where(deleted: false).group(:name).collect(&:id)
category.products.where("products.id IN (?)", ids).find_active
How can we optimize the queries?

You can do Product.all.pluck(:name).uniq to get just the product names in an array.
But I think you're solving the wrong problem, in that this problem has a bad 'smell'. If you have products that have identical names, how do you differentiate them from a UX perspective? And why only get the first created product by that name vs. the most 'popular' product? I'm trying to imagine how this solution would work for the user and I'm coming up blank, perhaps because I don't know enough about the context.
Edit: Also, could you clarify what you mean by 'should not have duplicate product name'? Is it to get a list of products, but only the first product if there's multiple products with the same name? Or are you looking for items to correct?

The simple solution in Postgres is with DISTINCT ON:
SELECT DISTINCT ON (name)
id, name -- add more columns if you need
FROM Product
WHERE deleted = FALSE
ORDER BY name, id;
Returns unique product names (sorted alphabetically). From each set of dupes the one with the smallest id. Details:
Select first row in each GROUP BY group?

Related

Iterate over a list in Neo4j

I am working on Neo4j database and I want to replicate the scenario mentioned below,
I have 2 nodes Product and customer. In the customer node I am storing customer id and list of products. and in the product I am storing only productid.
Customer has values {custId:1,products:[1,2,3,4]}
Product has values {productid:1},{productid:2},{productid:3},{productid:4}
Now what I want to do is,
I need to replace all these ids to an autogenerated ids after adding the nodes in the graph database. SOmething like set custId=ID(customer) and productId=ID(product) but what I am stuck at is how to iterate the list of products in customer node and change the product id to auto generated ids.
Any help is appreciated.
The idea of storing the product IDs are automatically generated by database in an array of user property - it is the wrong idea. In all senses.
The graph spirit - is to establish a relationship between the node Customer and its corresponding nodes Product, and then delete the property products from Customer and productid from Product:
MATCH (Customer:Customer)
UNWIND Customer.products as prodID
MATCH (Product:Product {productid: prodID})
MERGE (Customer)-[r:hasProduct]->(Product)
WITH Customer, count(Product) as mergedProduct
REMOVE Customer.products
WITH count(Customer) as totalMerged
MATCH (Product:Product)
REMOVE Product.productid

Retrive records which are not referenced in other table, ActiveRecord query

There are 2 tables : User and Teacher. Teacher.user_id is from User. So, how do I find in a single query, all the users who are not in teachers.
I meant something along the lines :
User.not_in(Teacher.all)
You can use where.not query from ActiveRecord try something like below:
User.where.not(id: Teacher.pluck(:user_id).reject {|x| x.nil?})
Note: used reject method, in case you have nil values in some records.
The other users seem to have neglected the rails 3 tag (since removed based on the approved answer. My answer left for posterity) : Please try this
User.where("id NOT IN (?)",Teacher.pluck(:user_id).join(","))
This will become SELECT * FROM users WHERE id NOT IN (....) (two queries one to get the user_id from teachers and another to get the user(s) not in that list) and may fail based on the size of teacher table.
Other option is an arel table:
users = User.arel_table
User.where(users[:id].not_in(Teacher.select(:user_id).where("user_id IS NOT NULL")))
This should produce a single query similar to
SELECT * FROM users
WHERE id NOT IN ( SELECT user_id FROM teachers WHERE user_id IS NOT NULL)
(one query better performance) * syntax was not fully tested
Another single query option might be
User.joins("LEFT OUTER JOIN teachers ON teachers.user_id = users.id").
where("teachers.user_id IS NULL")
I think you should be able to do something like this
User.where.not(id: Teacher.ids)

Clean and concise way to find active records that have the same id as another set of active records

I have a table called shoppers and another table called Users. I have a shopper_id which is the foreign key in the Shoppers table and refers to the primary key id in the Users table.
I ran a query called #shoppers = shoppers.where("some condition")
This allowed me to get a set of shoppers who satisfy the condition. Next I would like to select those Users who have the same id as the shopper_id as the individual objects in #shoppers.
I know I could do this by writing a loop, but I am wondering if ruby on rails allows me to write a Users.where condition that can help me obtain the subset of user objects with the same id as shopper_id arranged in ascending order by the name field in the Users table.
Any ideas?
Try this.
#shoppers = Shopper.where("some condition")
#users = User.where(id: #shoppers.collect(&:shopper_id)).order('name asc')

How do I get an array of unique values in my controller that is NOT connected to a model?

I have a table named Donations which has a column named season. Season contains the actual season the donation was made in... like 2011 or 2010, etc.
I also have a controller named ReportController that would like to pass a unique list of seasons from the Donations table.
In the ReportController, how do I get an array of those unique values? Is there something like #valid_seasons = Donations.find(:all).unique{|x| x.season} that I use in my reportcontroller? Will I then be able to pass #valid_seasons as an option for select statement in the views/report/foo.html.erb file?
You can use uniq_by
Donations.all.uniq_by{|x| x.season}
However this still executes a select * on your table.
You might be better off with using raw sql. Something like:
Donations.find_by_sql("SELECT * FROM donations GROUP BY season")
The first example will retrieve all the records and then filter. The second will only fetch the first row for each unique season.
You don't mention if this is rails 3 but, if so, this should do the trick:
Donations.select(:season).group(:season)
This will execute a proper group by:
SELECT season FROM "donations" GROUP BY season

Rails 3 Select Distinct Order By Number of Occurrences

In one of my models I have a country column. How would I go about selecting the top 3 countries based on how many models have that country?
Without any further information you can try this out:
YourModel.group('country').order('count_country DESC').limit(3).count('country')
when you call count on a field rails automatically adds an AS count_field_name field to your query.
Count must be called at the end of the query because it returns an ordered hash.

Resources