2015-09-04 2 views
4

У меня есть модель вызова рельсов MentorData, и она имеет атрибут os_usage. Озы хранятся в таком массиве, как ['apple', 'linux'].Как я могу запросить данные Rails ActiveRecord, хранящиеся в массивах

Резюмируя:

$ MentorData.first.os_usage 
=> ['apple', 'linux'] 

Я ищу, чтобы иметь возможность запрашивать данные для всех MentorData, что включает в os_usage из apple, но когда я ищу MentorData.where(os_usage: 'apple') я получаю только наставники, которые могут использовать только яблоко и не яблоко и linux. Мне нужно каким-то образом найти, что проверяет, включено ли яблоко в массив.

Я также пробовал следующее.

MentorData.where('os_usage like ?', 'apple’) 
MentorData.where('os_usage contains ?', 'apple’) 
MentorData.where('os_usage contains @>ARRAY[?]', 'apple') 

Возможно ли запрашивать данные в ActiveRecord с помощью атрибутов, имеющих массив или элементы?

База данных находится в Postgres, если это помогает в предоставлении более грубого поискового запроса.

+0

Путеводители Rails расскажут, как это сделать, и многих других Postgr Операции, специфичные для eSQL: http://edgeguides.rubyonrails.org/active_record_postgresql.html –

ответ

11

Вот примеры, приведенные в текущем Rails Edge Guides:

# db/migrate/20140207133952_create_books.rb 
create_table :books do |t| 
    t.string 'title' 
    t.string 'tags', array: true 
    t.integer 'ratings', array: true 
end 
add_index :books, :tags, using: 'gin' 
add_index :books, :ratings, using: 'gin' 

# app/models/book.rb 
class Book < ActiveRecord::Base 
end 

# Usage 
Book.create title: "Brave New World", 
      tags: ["fantasy", "fiction"], 
      ratings: [4, 5] 

## Books for a single tag 
Book.where("'fantasy' = ANY (tags)") 

## Books for multiple tags 
Book.where("tags @> ARRAY[?]::varchar[]", ["fantasy", "fiction"]) 

## Books with 3 or more ratings 
Book.where("array_length(ratings, 1) >= 3") 
0

Для подобных запросов вам нужно %% указать, что текст может отображаться слева или справа от вашего поиска.

Итак, попробуйте

MentorData.where('os_usage LIKE "%apple%"')

и посмотреть, если это работает.

Это дикий поиск карты, но опуская% работает как =

Смотрите этот вопрос: SQL LIKE with no wildcards the same as '='?

Это предполагает os_usage сериализованный массив, где столбец подложки, что данные строка, рельсы десериализует при создании экземпляра MentorData

Edit: я бы узнать, как ваша БД хранит массив, так что, может быть, вы могли бы сделать

"%'apple'%" 

, чтобы убедиться, что он не выбирает oses с яблоком, содержащимся только в названии.

+1

Мне пришлось внести изменения, но '%' работал. MentorData.where ('os_usage LIKE?', "% Apple%") – bdougie

+1

Другое примечание: ActiveRecord фактически делает массив строкой, поэтому это работает – bdougie

+0

@mu слишком короткое, извините. Я сделал предположение, что os_usage - это сериализованный столбец, который хранится в виде строки, а затем десериализован обратно в массив. brianllamar, рад, что это сработало :-) – NullVoxPopuli

1

Возможно, вам следует отделить массив os_usage от вашей модели и сделать его отдельной таблицей.

В ActiveRecord мире вы получите что-то вроде следующего кода:

class MentorData < ActiveRecord::Base 
    .. 
    has_and_belongs_to_many :os_usage 
    .. 
end 

class OsUsage < ActiveRecord::Base 
    .. 
    has_and_belongs_to_many :mentors_data 
    .. 
end 

Создание many_to_many отношений между этими двумя моделями, позволяет легко запрашивать и избежать дублирования. Этот метод называется нормализация.

Используя этот новый дизайн у вас есть ваша коллекция os_usage сделаны объекты вместо строк

MentorData.first.os_usage 
# => [#<OsUsage:....>, #<OsUsage:...>] 

Что вы можете преобразовать легко в старый массив строк

MentorData.first.os_usage.map(&:name) 
# => ['apple', 'linux'] 

Кроме того, вы можете запросить данные для всех MentorData, которые включают os_usage яблоко:

MentorData.joins(:os_usages).where('os_usages.name' => 'apple') 

А также запросить все записи MentorData в течение OsUsage:

OsUsage.where(name: 'apple').mentors_data 

Я надеюсь, что вы найдете ее полезной :)

+0

Это отличная запись и имеет большой смысл. Это похоже на лучший подход, чем мой текущий. – bdougie

Смежные вопросы