Запрос массива mysql json к другому массиву в ActiveRecord - PullRequest
1 голос
/ 21 января 2020

Я пытаюсь запросить базу данных mysql. Мне нужно только вернуть значения, которые присутствуют во внешнем массиве:

query_data = tours.select(:orders)

=> [#<Tour:0x007fd1b0972438 orders: [223597]>, ...]

У меня есть внешний массив, который выглядит следующим образом: orders = [223597, 223598]

Прямо сейчас я использую ruby для фильтрации данных, но это не так эффективно, как хотелось бы:

query_data = query_data.find_all do |data|
  data.orders.any? { |o| orders.include?(o) }
end

Итак, мой вопрос, как я могу проверить массив базы данных по массиву ордеров и вернуть только записи с эти идентификаторы присутствуют в массиве базы данных, используя только SQL?

Я пытался что-то подобное, но я не думаю, что это был правильный способ сделать это:

query_data.where("JSON_EXTRACT('tour.orders', '$[*]') IN #{orders}")

Плюс, это просто прямо не работает.

Версии:

Ruby: 2.3.1
mysql: mysql  Ver 14.14 Distrib 5.7.29, for osx10.14 (x86_64) using  EditLine wrapper
Rails: 5

1 Ответ

0 голосов
/ 21 января 2020

Использование JSON_EXTRACT() в предложении WHERE запроса SQL гарантирует, что он не сможет использовать индекс. Так что он собирается сделать сканирование таблицы, которое не более эффективно.

В общем, я рекомендую разработчикам, у которых в базе данных есть столбец JSON:

Вы можете извлечь часть JSON документа в списке SELECT:

SELECT JSON_EXTRACT(tour.orders, '..expr..') FROM ...

Но не делайте этого ни в одном другом пункте вашего запроса SQL. Ни в предложении WHERE, ни в выражении JOIN, ни в GROUP BY, ORDER BY, HAVING и т. Д. c. Есть много случаев, которые нельзя оптимизировать, и это делает ваши SQL запросы очень сложными, трудными для кодирования, трудными для чтения и сложными для обслуживания.

Вместо этого, если вы хотите сравнить с отдельными элементы массива JSON, вы должны хранить их в нормализованном порядке, по одному элементу на строку в дочерней таблице.

Например, у вас может быть таблица tour_orders, где каждая строка имеет ссылку на tour.id и один идентификатор заказа. Затем вы можете запросить его более читабельным способом:

query_data.where(order: orders)

Использование типа данных JSON в MySQL упрощает вставку большого количества данных, но усложняет многие типы запросов. Я рекомендую избегать типа данных JSON, если вам нужны выражения SQL для доступа к отдельным элементам JSON документа.

...