सबसे पहले, आप इस तरह JSON सरणी मानों तक नहीं पहुंच सकते हैं। किसी दिए गए json मान के लिए
[{"event_slug":"test_1","start_time":"2014-10-08","end_time":"2014-10-12"},
{"event_slug":"test_2","start_time":"2013-06-24","end_time":"2013-07-02"},
{"event_slug":"test_3","start_time":"2014-03-26","end_time":"2014-03-30"}]
पहले सरणी तत्व के विरुद्ध एक मान्य परीक्षण होगा:
WHERE e->0->>'event_slug' = 'test_1'
लेकिन आप शायद अपनी खोज को सरणी के पहले तत्व तक सीमित नहीं करना चाहते हैं। jsonb
. के साथ Postgres 9.4 में डेटा प्रकार आपके पास अतिरिक्त ऑपरेटर और अनुक्रमणिका समर्थन है। किसी सरणी के तत्वों को अनुक्रमित करने के लिए आपको एक GIN अनुक्रमणिका की आवश्यकता होती है।
GIN इंडेक्स के लिए बिल्ट-इन ऑपरेटर क्लासेस "इससे बड़ा" या "इससे कम" ऑपरेटर्स का समर्थन नहीं करते हैं <स्ट्राइक> > >= < <=
स्ट्राइक> . यह jsonb
. के लिए सही है साथ ही, जहां आप दो ऑपरेटर वर्गों के बीच चयन कर सकते हैं। प्रति दस्तावेज़:
Name Indexed Data Type Indexable Operators
...
jsonb_ops jsonb ? ?& ?| @>
jsonb_path_ops jsonb @>
(jsonb_ops
डिफ़ॉल्ट होने के नाते।) आप समानता परीक्षण को कवर कर सकते हैं, लेकिन इनमें से कोई भी ऑपरेटर >=
के लिए आपकी आवश्यकता को कवर नहीं करता है। तुलना। आपको एक btree अनुक्रमणिका की आवश्यकता होगी।
मूल समाधान
इंडेक्स के साथ समानता जांच का समर्थन करने के लिए:
CREATE INDEX locations_events_gin_idx ON locations
USING gin (events jsonb_path_ops);
SELECT * FROM locations WHERE events @> '[{"event_slug":"test_1"}]';
यदि फ़िल्टर पर्याप्त रूप से चयनात्मक है तो यह काफी अच्छा हो सकता है।
मान लें कि end_time >= start_time
, इसलिए हमें दो चेक की आवश्यकता नहीं है। केवल end_time
की जांच की जा रही है सस्ता और समकक्ष है:
SELECT l.*
FROM locations l
, jsonb_array_elements(l.events) e
WHERE l.events @> '[{"event_slug":"test_1"}]'
AND (e->>'end_time')::timestamp >= '2014-10-30 14:04:06 -0400'::timestamptz;
एक अंतर्निहित JOIN LATERAL
का उपयोग करना . विवरण (अंतिम अध्याय):
- तत्व संख्या के साथ PostgreSQL unnest()
विभिन्न डेटा प्रकारों से सावधान रहें ! आपके पास JSON मान में जो है वह timestamp [without time zone]
. जैसा दिखता है , जबकि आपके विधेय timestamp with time zone
. का उपयोग करते हैं शाब्दिक। timestamp
मान की व्याख्या वर्तमान समय क्षेत्र . के अनुसार की जाती है सेटिंग, जबकि दिया गया timestamptz
अक्षर timestamptz
. पर डाले जाने चाहिए स्पष्ट रूप से या समय क्षेत्र पर ध्यान नहीं दिया जाएगा! उपरोक्त क्वेरी को वांछित के रूप में काम करना चाहिए। विस्तृत विवरण:
- रेल और पोस्टग्रेएसक्यूएल में टाइम ज़ोन को पूरी तरह नज़रअंदाज़ करना
jsonb_array_elements()
. के लिए अधिक स्पष्टीकरण :
- JSONB का उपयोग करके PostgreSQL में शामिल होना
उन्नत समाधान
यदि उपरोक्त पर्याप्त नहीं है, तो मैं एक MATERIALIZED VIEW
पर विचार करूंगा जो प्रासंगिक विशेषताओं को सामान्यीकृत रूप में संग्रहीत करता है। यह सादे btree अनुक्रमणिका की अनुमति देता है।
कोड मानता है कि आपके JSON मानों का प्रारूप एक समान है जैसा कि प्रश्न में दिखाया गया है।
सेटअप:
CREATE TYPE event_type AS (
, event_slug text
, start_time timestamp
, end_time timestamp
);
CREATE MATERIALIZED VIEW loc_event AS
SELECT l.location_id, e.event_slug, e.end_time -- start_time not needed
FROM locations l, jsonb_populate_recordset(null::event_type, l.events) e;
jsonb_populate_recordset()
. के लिए संबंधित उत्तर :
- PostgreSQL 9.4 के jsonb टाइप को फ्लोट में कैसे बदलें
CREATE INDEX loc_event_idx ON loc_event (event_slug, end_time, location_id);
location_id
. सहित भी केवल-अनुक्रमणिका स्कैन की अनुमति देने के लिए . (मैन्युअल पेज देखें और विकी पोस्ट करें।)
प्रश्न:
SELECT *
FROM loc_event
WHERE event_slug = 'test_1'
AND end_time >= '2014-10-30 14:04:06 -0400'::timestamptz;
या, यदि आपको अंतर्निहित locations
. से पूर्ण पंक्तियों की आवश्यकता है टेबल:
SELECT l.*
FROM (
SELECT DISTINCT location_id
FROM loc_event
WHERE event_slug = 'test_1'
AND end_time >= '2014-10-30 14:04:06 -0400'::timestamptz
) le
JOIN locations l USING (location_id);