私は同じ問題を経験し、次に Joachim Jablon のコードを試してみました。うまく機能しているように見えましたが、まだ問題がありました。ここで要点を説明します。最長バージョンは私のブログにあります。
SELECT '{"a":1,"b":2}'::json = '{"b":2,"a":1}'::json
false
文字列表現に基づいているため、 が返されます。
hash
演算子クラスがの代わりにあるため、フィールドの並べ替えは許可されませんbtree
。
次に、json_cmp()
PL/V8 で関数を作成しました。これは、btree に必要な演算子を強化するために使用できます。
これが完全なSQLスクリプトです
CREATE OR REPLACE FUNCTION json_cmp(left json, right json)
RETURNS integer AS $$
function cleverType(obj) {
var type = typeof obj;
if (type === 'object') {
if (obj === null) {
type = 'null';
} else if (obj instanceof Array) {
type = 'array';
}
}
return type;
}
function cmp(left, right) {
var leftType = cleverType(left),
rightType = cleverType(right),
i,
buf,
leftKeys,
rightKeys,
output = 0;
if (leftType !== rightType) {
output = leftType.localeCompare(rightType);
} else if (leftType === 'number'
|| leftType === 'boolean'
|| leftType === 'string') {
if (left < right) {
output = -1;
} else if (left > right) {
output = 1;
} else {
output = 0;
}
} else if (leftType === 'array') {
if (left.length !== right.length) {
output = cmp(left.length, right.length);
} else {
for (i = 0; i < left.length; i += 1) {
buf = cmp(left[i], right[i]);
if (buf !== 0) {
output = buf;
break;
}
}
}
} else if (leftType === 'object') {
leftKeys = Object.keys(left);
rightKeys = Object.keys(right);
if (leftKeys.length !== rightKeys.length) {
leftKeys.sort();
rightKeys.sort();
buf = cmp(leftKeys, rightKeys);
} else {
buf = cmp(leftKeys.length, rightKeys.length);
}
if (buf !== 0) {
output = buf;
} else {
for (i = 0; i < leftKeys.length; i += 1) {
buf = cmp(left[leftKeys[i]], right[leftKeys[i]]);
if (buf !== 0) {
output = buf;
break;
}
}
}
}
return output;
}
return cmp(left, right);
$$ LANGUAGE plv8 IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION json_eq(json, json)
RETURNS BOOLEAN LANGUAGE SQL STRICT IMMUTABLE AS $$
SELECT json_cmp($1, $2) = 0;
$$;
CREATE OR REPLACE FUNCTION json_lt(json, json)
RETURNS BOOLEAN LANGUAGE SQL STRICT IMMUTABLE AS $$
SELECT json_cmp($1, $2) < 0;
$$;
CREATE OR REPLACE FUNCTION json_lte(json, json)
RETURNS BOOLEAN LANGUAGE SQL STRICT IMMUTABLE AS $$
SELECT json_cmp($1, $2) <= 0;
$$;
CREATE OR REPLACE FUNCTION json_gt(json, json)
RETURNS BOOLEAN LANGUAGE SQL STRICT IMMUTABLE AS $$
SELECT json_cmp($1, $2) > 0;
$$;
CREATE OR REPLACE FUNCTION json_gte(json, json)
RETURNS BOOLEAN LANGUAGE SQL STRICT IMMUTABLE AS $$
SELECT json_cmp($1, $2) >= 0;
$$;
CREATE OPERATOR = (LEFTARG = json, RIGHTARG = json, PROCEDURE = json_eq);
CREATE OPERATOR < (LEFTARG = json, RIGHTARG = json, PROCEDURE = json_lt);
CREATE OPERATOR <= (LEFTARG = json, RIGHTARG = json, PROCEDURE = json_lte);
CREATE OPERATOR > (LEFTARG = json, RIGHTARG = json, PROCEDURE = json_gt);
CREATE OPERATOR >= (LEFTARG = json, RIGHTARG = json, PROCEDURE = json_gte);
CREATE OPERATOR CLASS json_ops
DEFAULT FOR TYPE json USING btree AS
OPERATOR 1 <,
OPERATOR 2 <=,
OPERATOR 3 =,
OPERATOR 4 >=,
OPERATOR 5 >,
FUNCTION 1 json_cmp(json, json);
もちろん、これは単純な文字列比較よりもはるかに遅くなる傾向がありますが、より堅牢な結果が得られるという利点があります。
移行に South を使用する場合は、空の移行を作成し、forwards()
メソッドから SQL を実行できることに注意してください。これにより、アプリを移行するときに関数が自動的にインストールされます。