2

Let's say I have the table recipes with the column ingredients, jsonb column type. Example record:

{
  id: 1,
  ingredients: [
    'eggs',
    'fragrant bread',
    'fresh tomatoes'
  ]
}

How can I retrieve the record with substring in where conditions? For example:

ingredients = ['egg', 'tomato']
Recipe.where('ingredients ?& array[:keys]', keys: ingredients)

I was trying:

ingredients = ['egg', 'tomato']
Recipe.where("ingredients @> ARRAY[?]::varchar[]", ingredients).count

But I'm getting this error:

ERROR:  operator does not exist: jsonb @> character varying[] (PG::UndefinedFunction)
2
  • You can simply cast array to text then search with [I]LIKE. e.g. SELECT * FROM (SELECT '["eggs", "with meatballs", "balls without meat"]'::text as col) foo where col ILIKE '%eat%'. Injecting that query to rails should be easy. Plz let me know if that works for you. Commented Oct 26, 2021 at 9:16
  • @spirito_libero please checkout this stackoverflow.com/a/34060269/5580690 . Hope you will find this helpful. Commented Oct 27, 2021 at 14:46

1 Answer 1

1

I would really consider just using two tables instead as this stinks of the unnesiccary JSON antipattern.

class Recipe
  has_many :recipe_ingredients
  has_many :recipes, through: :recipe_ingredients

  def self.with_ingredients(*ingredients)
    binds = Array.new(ingredients.length, '?')
    sql = "ingredients.name ILIKE ANY(ARRAY[#{binds.join(,)}])"
    joins(:ingredients)
      .where(
        sql,
        *ingredients.map { |i| "'%#{i}%'" }
      )
  end
end
class RecipeIngredient
  belongs_to :ingredient
  belongs_to :recipe
end
class Ingredient
  has_many :recipe_ingredients
  has_many :recipes: through: :recipe_ingredients
end

This lets you use an effective index on recipies.name, sane queries and avoids denormalization.

Sign up to request clarification or add additional context in comments.

Comments

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.