Хэш фильтра с JsonPath

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

Нужно получить тег tire, где grip == 'bad'

require "jsonpath"

hash = {
    :id => 1,
    :cars => [
        {:id => 1, :tire => {:grip => "good", :color => "black"}},
        {:id => 2, :tire => {:grip => "bad", :color => "red"}},
        {:id => 3, :tire => {:grip => "good", :color => "green"}}
    ]
}

puts JsonPath.on(hash, "$..tire[?(@['grip'] == 'bad')]").inspect

Нет результатов.


person Artem Kalinchuk    schedule 16.11.2012    source источник
comment
Что такое тег tire? Что такое grip? У вас есть :grip в вашем хэше и 'grip' в вашем коде My; это как-то связано с чем-то из этого? Что такое THE_HASH?   -  person sawa    schedule 16.11.2012
comment
Тег tire является одним из ключей в приведенном выше хэше. 'grip' и :grip не имеют значения для jsonpath. THE_HASH — это хэш, который я разместил выше.   -  person Artem Kalinchuk    schedule 16.11.2012


Ответы (2)


Фильтр [?()] работает только для массивов (или, по крайней мере, либо для массивов, либо для хэшей, а не для того и другого одновременно). Чтобы это сработало, мне пришлось заключить хэш :tire в массив.

Оригинал:

:tire => {:grip => "good", :color => "black"}

Новый:

:tire => [{:grip => "good", :color => "black"}]

Это «исправление», которое работает для меня. Было бы лучше, если бы кто-нибудь починил гем jsonpath, чтобы он работал и для массивов, и для хэшей (одного типа и в одно и то же время).

person Artem Kalinchuk    schedule 20.12.2012
comment
Было бы здорово, если бы он мог работать как с массивами, так и с хэшами. Знаете ли вы что-нибудь, что преобразует каждый элемент JSON в массив, если это еще не так? - person Trinculo; 23.12.2015

В JsonPath.on первым аргументом должен быть json, а не хеш.
Я не могу сделать это с ruby, это не совсем правильное решение. Но может быть это поможет вам.

require 'jsonpath'
require 'json'

hash = {
    :id => 1,
    :cars => [
        {:id => 1, :tire => {:grip => "good", :color => "black"}},
        {:id => 2, :tire => {:grip => "bad", :color => "red"}},
        {:id => 3, :tire => {:grip => "good", :color => "green"}}
    ]
}

json = hash.to_json
obj = JsonPath.new( "$..tire")[json]
result = obj.inject(Array.new){|res, x| res << x if x["grip"]=='bad'; res }

p result # [{"grip"=>"bad", "color"=>"red"}]
person Alexander Randa    schedule 16.11.2012
comment
Вы пробовали это с драгоценным камнем jsonpath? Я отредактировал свой вопрос, значения захвата на самом деле являются строками. - person Artem Kalinchuk; 16.11.2012
comment
Вы пробовали второе решение? Пожалуйста, проверьте, прежде чем публиковать ответы. - person Artem Kalinchuk; 16.11.2012
comment
Нет, это не решение, к сожалению. Я не знаю, как написать правильный JsonPath. Извиняюсь. - person Alexander Randa; 16.11.2012
comment
Я разместил код в вопросе. Вы можете поэкспериментировать с этим кодом. - person Artem Kalinchuk; 19.11.2012
comment
Я обновляю свой код (добавляю хеш и исправляю печать). Теперь этот код возвращает массив с нужной шиной. - person Alexander Randa; 19.11.2012
comment
Это решение работает, но 1. Это в основном хак для JsonPath и 2. Это не сработает, если у car было более одной шины. Например: :tire => [{:grip => "good"}, {:grip => "bad"}]. Мне нужно, чтобы поймать оба сценария. - person Artem Kalinchuk; 20.11.2012
comment
Я бы сказал, не верное решение. Хэш нельзя просто преобразовать в JSON. Причин много: 1) рубиновый хэш может иметь сложную структуру в качестве ключа, как и другой хеш; 2) значения могут быть замыканиями (например, лямбдами) 3) хэши могут иметь циклы. - person ribamar; 24.10.2018
comment
Первым аргументом JsonPath.on() может быть хеш, но хеш-ключи не могут быть символами, они должны быть строками. Если вы stringify_keys, это сработает. Внутренне JsonPath использует объект Hash/Array, и если вы передадите ему Hash/Array вместо String, который обходит декодирование JSON, которое он делает: github.com/joshbuddy/jsonpath/blob/ - person lamont; 29.10.2019