जांचें कि क्या Postgres JSON सरणी में स्ट्रिंग है


121

मेरे पास अपने खरगोशों के बारे में जानकारी संग्रहीत करने के लिए एक मेज है। यह इस तरह दिख रहा है:

create table rabbits (rabbit_id bigserial primary key, info json not null);
insert into rabbits (info) values
  ('{"name":"Henry", "food":["lettuce","carrots"]}'),
  ('{"name":"Herald","food":["carrots","zucchini"]}'),
  ('{"name":"Helen", "food":["lettuce","cheese"]}');

मुझे उन खरगोशों को कैसे खोजना चाहिए जो गाजर पसंद करते हैं? मैं इसके साथ आया:

select info->>'name' from rabbits where exists (
  select 1 from json_array_elements(info->'food') as food
  where food::text = '"carrots"'
);

मुझे वह क्वेरी पसंद नहीं है। यह एक गड़बड़ है।

पूर्णकालिक खरगोश-रक्षक के रूप में, मेरे पास अपने डेटाबेस स्कीमा को बदलने का समय नहीं है। मैं बस अपने खरगोशों को ठीक से खिलाना चाहता हूं। क्या उस क्वेरी को करने के लिए अधिक पठनीय तरीका है?


1
दिलचस्प सवाल। मैंने इसके साथ खेला है, लेकिन फिर यह मुझ पर छा गया, मुझे यकीन नहीं है कि आप "बेहतर" से क्या मतलब है। आप अपने जवाबों को किस मापदंड से देखते हैं? पठनीयता? दक्षता? अन्य?
डेविड एस

@ डेविड: (मैंने प्रश्न को अद्यतन किया।) मैं दक्षता पर पठनीयता पसंद करूंगा। मैं निश्चित रूप से एक पूर्ण तालिका स्कैन से बेहतर कुछ भी उम्मीद नहीं करता हूं, क्योंकि मैं स्कीमा तय कर रहा हूं।
स्नोबॉल

11
क्या यह गलत है कि मैंने खरगोशों की वजह से इस सवाल को उठाया?
ओसमैन

3
मैंने सिर्फ खरगोशों के कारण इस सवाल को उठाया और फिर आपकी टिप्पणी देखी @osman
1valdis

मैंने आपकी टिप्पणी देखी और फिर महसूस किया कि मुझे खरगोशों के कारण उखाड़ने की आवश्यकता है
पीटर एरोन ज़ेंटई

जवाबों:


186

PostgreSQL 9.4 के अनुसार, आप ?ऑपरेटर का उपयोग कर सकते हैं :

select info->>'name' from rabbits where (info->'food')::jsonb ? 'carrots';

यदि आप इसके बजाय jsonb प्रकार पर स्विच करते हैं, तो आप ?क्वेरी को "food"कुंजी पर अनुक्रमित कर सकते हैं :

alter table rabbits alter info type jsonb using info::jsonb;
create index on rabbits using gin ((info->'food'));
select info->>'name' from rabbits where info->'food' ? 'carrots';

बेशक, आपके पास पूर्णकालिक खरगोश कीपर के रूप में संभवतः उसके लिए समय नहीं है।

अपडेट: यहां 1,000,000 खरगोशों की मेज पर प्रदर्शन में सुधार का प्रदर्शन है, जहां प्रत्येक खरगोश को दो खाद्य पदार्थ पसंद हैं और उनमें से 10% गाजर की तरह हैं:

d=# -- Postgres 9.3 solution
d=# explain analyze select info->>'name' from rabbits where exists (
d(# select 1 from json_array_elements(info->'food') as food
d(#   where food::text = '"carrots"'
d(# );
 Execution time: 3084.927 ms

d=# -- Postgres 9.4+ solution
d=# explain analyze select info->'name' from rabbits where (info->'food')::jsonb ? 'carrots';
 Execution time: 1255.501 ms

d=# alter table rabbits alter info type jsonb using info::jsonb;
d=# explain analyze select info->'name' from rabbits where info->'food' ? 'carrots';
 Execution time: 465.919 ms

d=# create index on rabbits using gin ((info->'food'));
d=# explain analyze select info->'name' from rabbits where info->'food' ? 'carrots';
 Execution time: 256.478 ms

उन पंक्तियों को कैसे प्राप्त किया जाए जहाँ जौन के अंदर की खाद्य सरणी खाली न हो, उदाहरण के लिए यदि हम विचार कर सकते हैं, तो उनका नाम JSON है, जहाँ भोजन की सरणी भी खाली है, क्या आप मदद कर सकते हैं
ब्रावो

1
@ ब्रावोselect * from rabbits where info->'food' != '[]';
स्नोबॉल

1
क्या किसी को पता है कि यह कैसे काम करता है अगर आपको स्ट्रिंग / पाठ के बजाय पूर्णांक का चयन करने की आवश्यकता है?
रोटेरेटी

3
@Rotareti आप उपयोग कर सकते हैं @> ऑपरेटर : create table t (x jsonb); insert into t (x) values ('[1,2,3]'), ('[2,3,4]'), ('[3,4,5]'); select * from t where x @> '2';। ध्यान दें कि '2'एक JSON नंबर है; उद्धरण द्वारा भ्रमित न हों।
स्नोबॉल

@Snowball, इस प्रश्न का चयन करें जानकारी - >> 'नाम' खरगोशों से कहाँ (जानकारी -> 'भोजन') :: jsonb? 'गाजर'; JSON से खोज शब्द के लिए एकदम सही काम कर रहा है। लेकिन मैं कैसे सभी रिकॉर्ड प्राप्त कर सकता हूं जिसमें 'गाजर' शब्द शामिल नहीं है?
मिलान

23

आप ऐसा कुछ करने के लिए @> ऑपरेटर का उपयोग कर सकते हैं

SELECT info->>'name'
FROM rabbits
WHERE info->'food' @> '"carrots"';

1
यह तब उपयोगी होता है जब आइटम अशक्त हो
Lucio

2
सुनिश्चित करें कि आप '"गाजर" के आस-पास के टिक्स पर ध्यान देते हैं ... यदि आप एक पूर्णांक के लिए जाँच कर रहे हैं तो भी यह टूट जाता है। (एक पूर्णांक खोजने के लिए 3 घंटे बिताने की कोशिश की, यह जादुई रूप 'से संख्या के चारों ओर टिक्स लपेटकर काम कर रहा है )
skplunkerin

@skplunkerin 'एक स्ट्रिंग बनाने के लिए टिक्स से घिरा json मान होना चाहिए , क्योंकि JSON प्रकार में SQL के लिए सब कुछ एक स्ट्रिंग है। उदाहरण के लिए, बूलियन:, 'true'स्ट्रिंग:, '"example"'पूर्णांक '123':।
अवधी

22

होशियार नहीं बल्कि सरल:

select info->>'name' from rabbits WHERE info->>'food' LIKE '%"carrots"%';

13

एक छोटी सी भिन्नता लेकिन कुछ भी नया नहीं है। यह वास्तव में एक सुविधा याद आ रही है ...

select info->>'name' from rabbits 
where '"carrots"' = ANY (ARRAY(
    select * from json_array_elements(info->'food'))::text[]);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.