0

I have a category_aliases table, which has aliase column (array type), and category_id column, which points to categories table.

I have products table, which has category column.

I have categories table.

I want to loop through all products (a lot), which has old categories, and map these to new categories.

So I need to check if any of category_aliases.aliase (aliase is an array of old categories) includes this product's category, and if yes, I want to map it to new category from categories table.

What I tried is:

Product.all.each do |p|
  CategoryAlias.all.each do |ca|
    if ca.aliase.include? p.category
      p.update_column(:category, Category.find(ca.category_id).name)
    else
      p.update_column(:category, 'undefined')
    end
  end
end

But I am surely missing something, because even though I know, that there should almost always be a match, it updates p.category to 'undefined' all the time.

5
  • In such cases, I would go for puts/logger driven development; add a lot of puts or logger.info statements at each step, and pinpoint exactly where the expected output is different from actual output. :-) Commented Feb 15, 2015 at 20:34
  • Is your aliase an array inside the database or is it done using serialize (i.e. a blob of YAML inside the database)? Commented Feb 15, 2015 at 23:11
  • @muistooshort I use postgress, and store array in db (t.text :aliase, aray: true) Commented Feb 16, 2015 at 2:33
  • Why involve Ruby at all then? You should be able to do the whole thing inside the databases with SQL, no? Commented Feb 16, 2015 at 2:47
  • @muistooshort I 'm used to using Ruby, so would like to achieve it with that. But I'm sure you are right.. Commented Feb 16, 2015 at 3:01

2 Answers 2

2

You do not need to iterate through all categories ('each') in each product loop, you just need to find a matching category detect. Furthermore: if you need to iterate over many Products, is might be better to use find_each:

category_aliases = CategoryAlias.pluck(:name, :aliase)

Product.find_each do |product|
  category = category_aliases.detect { |ca| ca.aliase.include? product.category } 

  if category
    p.update_column(:category, cateory.name)
  else
    p.update_column(:category, 'undefined')
  end
end
Sign up to request clarification or add additional context in comments.

4 Comments

even though you've mixed some columns up,the idea is clear and it works like a charm! Thanks a bunch!
hey man, if you have few more minutes, please help me out with one more thing regarding the issue. Now I changed the products.category column to be an array. It is done, because there could a situation, where few ca.aliase. include product.category. How would i go with erasing old product.category, and then pushing new ones? Thanks a lot!
should I simply first push new categories into product.category array and then loop through products removing first, or there are a clever solution?
Sorry, but I don't understand your comment about new categories. Perhaps it is a good idea to write a new question with some code examples?
1

I see number of issues in the code:

  1. You updated category field on each iteration. It leads to update to 'undefined' if CategoryAlias record does not contain category. All other iterations do not make sense then.
  2. You need to break inner loop right after category is updated.
  3. You need to update category to 'undefined' in outer loop, if no alias category found in the whole category_aliases table.

3 Comments

category is a products column, so it is not a relation
I updated the answer, found a lot of issues in the code.
And, I think, that @spickermann's answer contains much better code for your case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.