Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

320
Views
Use Rails 'contains operator' (o alternativa) para buscar con múltiples valores

Tengo dos modelos: Autor y Libro, donde

 class Book< ApplicationRecord belongs_to :author end class Author< ApplicationRecord has_many :books end

El autor tiene un nombre: cadena

El libro tiene title:string y author_id como índice

Estoy interesado en encontrar todos los autores que tienen libros que contienen algunas cadenas dadas

por ejemplo, si los términos son ['mago', 'cien', 'dos ciudades'] quiero devolver los autores cuyos libros contienen los términos en el título (un título de libro que contiene 'mago' Y un libro que contiene 'cien' Y...)

Podría ir con algo como

 class Post scope :including_all_title, -> (titles) { where(matching_tag_query(titles, 'AND')) } private def matching_tag_query(titles, condition_separator = 'AND') titles.map { |t| "(title LIKE '%#{t}%')" }.join(" #{condition_separator} ") end end

( Author.joins(:books).merge(Books.inclusive_all_title... ) pero no parece muy bueno a medida que aumenta el número de términos.

He visto respuestas que contienen '@>' de Postgres (por ejemplo, Postgres: ¿verificar si el campo de matriz contiene valor? )

pero hasta ahora no pude hacerlo funcionar (probablemente la sintaxis no sea buena, no obtengo un error pero no resultados)

Me pregunto cómo podría lograr eso con Active Record (u otra solución mejor que la mía)

Editar : me doy cuenta de que podría no haber sido claro, lo que estoy tratando de hacer es: Si Author(name:'John') tiene libros Book(title: 'The wonderful Wizard of Oz') Book(title: 'Fantastic beasts') Book(title: 'Some other work') Book(title: 'Another book') y consulto por ["%wizard%", "%fantastic%"] Me gustaría encontrar el autor cuyos libros, coincida con TODOS las palabras clave, por lo que en este caso, John sería una coincidencia (porque "mago" coincide con un libro y "fantástico" coincide con otro, incluso si algunos no coinciden, estoy interesado en mis palabras clave)

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Esto debería funcionar:

 def matching_tag_query(titles, condition_separator = 'AND') titles.map { |t| "(title LIKE '%#{t}%')" }.join(" #{condition_separator} ") end

pero está sujeto a la inyección de SQL y puede hacerlo más limpio usando expr op any(array) y expr op all(array) de PostgreSQL con el operador ILIKE. Algo más como esto:

 scope :including_all_title, -> (titles) { where('title ilike all(array[?])', titles.map { |t| "%#{sanitize_sql_like(t)}%" }) scope :including_any_title, -> (titles) { where('title ilike any(array[?])', titles.map { |t| "%#{sanitize_sql_like(t)}%" })

Debería estar bien para titles realistas, pero si alguien le arroja un par de miles de titles , entonces podría encontrarse con límites de tamaño de consulta y no encontraría nada de todos modos.


En respuesta a los comentarios: si desea encontrar todos los libros que coincidan con alguna de las palabras clave, entonces:

 books = Book.where('title like any(array[?])', titles.map { |t| "%#{sanitize_sql_likt(t)}%" })

Luego para encontrar los autores:

 Author.where(id: books.select(:author_id))

Eso hará una subconsulta como esta:

 select * from authors where id in (select author_id from books where ...)

que no será tan eficiente como podría ser, pero debería ser lo suficientemente bueno. Si es demasiado lento, conviértalo en JOIN.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!