0

У меня проблема на обеих компьютерах Mac, но не на моих машинах Linux. не используя операторы сравнения даты, как это не работает на моем Mac:Postgres 9.5.3 Поля JSON, сравнивающие даты с операторами, странное поведение на Mac OSX 10

# Ruby code 
dt_start = DateTime.current - 10.days 
dt_end = DateTime.current 
id = 1 
# last_seen field looks like this in db when we store it: 
# {"1":"2016-11-21T22:17:47.269Z"} 
User.where("(last_seen->'?')::text <> 'null'", id 
).where("(last_seen->'?')::text > ?", id, dt_start 
).where("(last_seen->'?')::text <= ?", id, dt_end) 

SELECT "public"."users".* FROM "public"."users" WHERE ((last_seen->'1')::text <> 'null') AND ((last_seen->'1')::text > '2016-11-12 18:13:03.432534') AND ((last_seen->'1')::text <= '2016-11-22 18:13:03.432534') 

не возвращает записи на моем Mac, но работает на Linux

После разваливается этот запрос, когда я использую > оператора, я не независимо от того, какой диапазон дат я ставлю.

User.where("(last_seen->'?')::text > ?", id, 10.years.ago).count 
SELECT COUNT(*) FROM "public"."users" WHERE ((last_seen->'1')::text > '2006-11-22 23:46:59.199255') 
=> 0 

Когда я использую только оператор <, я получаю все записи, которые не имеют непустые last_seen полей независимо от того, какой даты я ставлю.

Я даже тестировал, переключая свое время на свой Mac, чтобы соответствовать часовому поясу linux box, который является UTC. Есть идеи?

UPDATE: Так DateTime и ActiveSupport :: TimeWithZone отформатирован ISO 8601 возвратных различных форматов:

DateTime.current.iso8601 # => "2016-11-23T19:18:36+00:00" 
Time.zone.now.iso8601 # => "2016-11-23T19:18:44Z" 

Поскольку last_seen JSON поля хранятся даты с использованием ActiveSupport :: TimeWithZone, я попытался изменить запросы SQL чтобы соответствовать этому формату, но та же проблема:

last_seen: {"1"=>"2016-10-20T14:30:00Z"}

SELECT COUNT(*) FROM "public"."users" WHERE ((last_seen->'1')::text <> 'null') AND ((last_seen->'1')::text > '2016-01-23T19:03:11Z') AND ((last_seen->'1')::text <= '2016-11-23T19:01:10Z') 
=> 0 

Затем я изменил last_seen JSON, чтобы иметь второй формат с DateTime, и задал вопрос с помощью DateTime с той же проблемой.

ответ

0

Вы говорите, что ваша колонка JSON содержит такие вещи, как:

{"1":"2016-11-21T22:17:47.269Z"} 

Значение в этом объекте является реальной ISO-8601 меткой времени. Запросы, которые ActiveRecord производит:

SELECT "public"."users".* 
FROM "public"."users" 
WHERE ... ((last_seen->'1')::text > '2016-11-12 18:13:03.432534') ... 

используют не совсем ISO-8601 метки времени, не хватает T между датой и временем компонентов в '2016-11-12 18:13:03.432534'. Результаты ваших сопоставлений text будут зависеть от того, как сравнивать 'T' и ' ', и это не гарантирует, что вы хотите, чтобы это было или даже было согласованным между платформами.

Если вы собираетесь делать такие вещи, вам нужно убедиться, что форматы согласованы. Я бы пошел со строгим ISO-8601, так как это формат True True Timestamp, и он будет вести себя повсеместно. Метод #iso8601 будет заботиться о форматировании для вас:

User.where("(last_seen->'?')::text <> 'null'", id) 
    .where("(last_seen->'?')::text > ?", id, dt_start.iso8601) 
    .where("(last_seen->'?')::text <= ?", id, dt_end.iso8601) 

Вызов #iso8601 себя даст ActiveRecord строку, так что вы будете шунтирование любой временной метки к строке форматирования AR хочет использовать. Также есть аргумент precision: iso8601, если вы не уверены в точности одной секунды.

Как вы считаете, вы уверены, что JSON - правильный подход к этому? Отдельная таблица может быть лучше подходит.

+0

обновленный ответ, да, я думаю, что я избавлюсь от этого, когда смогу и сделаю отдельную таблицу, или создаю представление или что-то еще – achabacha322

 Смежные вопросы

  • Нет связанных вопросов^_^