0

私のMacマシンでは問題はありますが、Linuxマシンでは問題があります。このように、日付の比較演算子を使用すると、私のMac上では動作しません:Postgres 9.5.3日付をオペレータと比較する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フィールドを持っていないすべてのレコードを取得します。

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') 
=> 42 

私は自分のMacで自分の時刻を自分のLinuxマシンのタイムゾーン(UTC)に合わせてテストしました。何か案は?

UPDATE: だから、日時とactivesupportの:: ISO 8601のリターンの異なる形式にフォーマットTimeWithZone:activesupportのを使用してlast_seen JSONフィールド保存された日付:: TimeWithZone以来

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

、私は、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の2番目の形式を変更し、代わりに同じ問題をDateTimeで照会しました。そのオブジェクトの値が本当のISO-8601のタイムスタンプである

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

答えて

0

はあなたのJSON列がのようなものが含まれていることを言います。 ActiveRecordのが生産されていることをクエリ:

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

は、かなり-ISO-8601でないタイムスタンプを使用している、いない '2016-11-12 18:13:03.432534'で日付と時刻のコンポーネント間行方不明 Ttextの比較の結果は、 'T'' 'の比較方法に左右されます。これは、プラットフォーム間で一貫性があるかどうかを保証するものではありません。

このようなことを行う場合は、フォーマットが一貫していることを確認する必要があります。私は厳密なISO-8601を持っています.1つのTrue Timestampフォーマットであり、どこでも一貫して動作します。あなたは、タイムスタンプ・ツー・文字列の書式ARを使用したいものは何でもバイパスますので、自分がActiveRecordのに文字列を与える#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方法はあなたのための書式設定を世話をします。また、1秒の精度では十分でない場合はprecisionの引数がiso8601になります。


JSONがこれに適切なアプローチであることは間違いありませんか?別のテーブルが適しているかもしれません。

+0

私はこれを取り除いて別のテーブルを作ったり、ビューや何かを作成したりするつもりです – achabacha322

関連する問題