2017-09-04 26 views
1

我想製作一個查詢在Ruby on Rails 5搜索jsonb字段,我需要找到所有記錄有一個發生在日期範圍內。Rails 5搜索jsonb嵌套數組之間的日期之間2其他dat

例如,查找發生在2017-08-01T12:00:002017-09-01T12:00:00之間的所有記錄。

{ 
    "repeats": { 
     "rrule": "FREQ=WEEKLY;DTSTART=20170904T030000Z;COUNT=20;INTERVAL=1;WKST=SU;BYDAY=MO", 
     "occurrences": [ 
      { 
       "uuid": "5445c067-1377-4636-9844-16b159caff1b", 
       "date_range": { 
        "end": "2017-09-04T14:00:00+10:00", 
        "start": "2017-09-04T13:00:00+10:00", 
        "timezone": "Australia/Melbourne" 
       } 
      }, 
      { 
       "uuid": "9a9a58ef-d697-4941-94d0-623915af87f3", 
       "date_range": { 
        "end": "2017-11-13T14:00:00+11:00", 
        "start": "2017-11-13T13:00:00+11:00", 
        "timezone": "Australia/Melbourne" 
       } 
      }, 
      { 
       "uuid": "4a310678-997a-4eb9-8bb9-faef80836c9f", 
       "date_range": { 
        "end": "2017-11-27T14:00:00+11:00", 
        "start": "2017-11-27T13:00:00+11:00", 
        "timezone": "Australia/Melbourne" 
       } 
      } 
     ] 
    }, 
    "tickets": { 
     "url": "", 
     "title": "" 
    }, 
} 

我敢在這裏使用開始輸了,所有我已經能夠做到的,是得到一個記錄,其中第一次出現開始不爲空(不是非常有用!):

posts = EventPost.where("document -> 'repeats' #> '{occurrences,0}' -> 'date_range' -> 'start' IS NOT NULL") 
+2

如果你需要做這種查詢,那麼你最好創建一個能夠響應date_range與時間對象的類,而不是將所有內容保存在jsonb字段中。 – EJ2015

+0

[Postgresql:Query Between time range using jsonb field]可能重複(https://stackoverflow.com/questions/30836025/postgresql-query-between-time-range-using-jsonb-field) – Robin

+1

如果可能,請遵循EJ2015的建議。請注意,杜松子索引類型對於這種類型的查詢來說基本上毫無價值,並且它最終將成爲每一次完整的表掃描。如果您可以將日期放入字段中,則可以使用對您的查詢有用的btree索引,使其顯着更快。 –

回答

0

你可以嘗試這樣來做:

start_datetime = DateTime.new(2017, 9, 4, 13) 
end_datetime = DateTime.new(2017, 9, 4, 14) 

EventPost.where(%{ 
    EXISTS (
    SELECT * FROM jsonb_array_elements(document #> '{repeats,occurrences}') occurrences 
    WHERE (occurrences -> 'date_range' ->> 'start')::timestamp >= ? 
     AND (occurrences -> 'date_range' ->> 'end')::timestamp <= ? 
) 
}, start_datetime, end_datetime) 

這將產生以下SQL:

SELECT "event_posts".* FROM "event_posts" WHERE (
    EXISTS (
    SELECT * FROM jsonb_array_elements(document #> '{repeats,occurrences}') occurrences 
    WHERE (occurrences -> 'date_range'->> 'start')::timestamp >= '2017-09-04 13:00:00' 
    AND (occurrences -> 'date_range' ->> 'end')::timestamp <= '2017-09-04 14:00:00' 
) 
) 

jsonb_array_elements()將JSON數組展開爲一組行。在PSQL它看起來像這樣:

{"uuid": "5445c067-1377-4636-9844-16b159caff1b", "date_range": {"end": "2017-09-04T14:00:00+10:00", "start": "2017-09-04T13:00:00+10:00", "timezone": "Australia/Melbou 
rne"}}          
{"uuid": "9a9a58ef-d697-4941-94d0-623915af87f3", "date_range": {"end": "2017-11-13T14:00:00+11:00", "start": "2017-11-13T13:00:00+11:00", "timezone": "Australia/Melbou 
rne"}}          
{"uuid": "4a310678-997a-4eb9-8bb9-faef80836c9f", "date_range": {"end": "2017-11-27T14:00:00+11:00", "start": "2017-11-27T13:00:00+11:00", "timezone": "Australia/Melbou 
rne"}}          
(3 rows) 

從這行我們只選擇那些符合條件,如果我們有什麼,EventPost被選中。

但我不認爲這是性能的最佳解決方案,因爲子查詢,類型轉換和jsonb處理。 @ EJ2015和@Michael Chaney給出了一個很好的建議,不要在jsonb中存儲startend

+0

最後我又走了一條路 - 我將他們從jsonb領域轉移到了一個單獨的課程中,這個課程要容易得多。 – JeremyKirkham