本文介绍了PostgreSQL:比较JSON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

众所周知,目前PostgreSQL无法比较两个json值。 json = json 之类的比较无效。但是之前将 json 强制转换为 text 怎么样?

As known, at the moment PostgreSQL has no method to compare two json values. The comparison like json = json doesn't work. But what about casting json to text before?

然后

select ('{"x":"a", "y":"b"}')::json::text =
('{"x":"a", "y":"b"}')::json::text

返回 true

同时

select ('{"x":"a", "y":"b"}')::json::text =
('{"x":"a", "y":"d"}')::json::text

返回 false

我尝试了一些具有更复杂对象的变体,它的工作原理是

I tried several variants with more complex objects and it works as expected.

此解决方案中是否有陷阱?

Are there any gotchas in this solution?

更新:

需要与v9.3兼容

推荐答案

是的您的方法存在多个问题(即转换为文本)。请考虑以下示例

Yes there are multiple problem with your approach (i.e. converting to text). Consider the following example

select ('{"x":"a", "y":"b"}')::json::text = ('{"y":"b", "x":"a"}')::json::text;

这类似于您的第一个示例,除了我翻转了 x y 键用于第二个对象,现在即使对象相等也返回false。

This is like your first example example, except that I flipped the order of the x and y keys for the second object, and now it returns false, even thought the objects are equal.

另一个问题是 json 保留空白,所以

Another issue is that json preserves white space, so

select ('{"x":"a", "y":"b"}')::json::text = ('{ "x":"a", "y":"b"}')::json::text;

返回false只是因为我在 x 在第二个对象中。

returns false just because I added a space before the x in the second object.

与v9.3配合使用的解决方案是使用 json_each_text 函数将两个JSON对象扩展到表中,然后比较两个表,例如像这样:

A solution that works with v9.3 is to use the json_each_text function to expand the two JSON objects into tables, and then compare the two tables, e.g. like so:

SELECT NOT exists(
    SELECT
    FROM json_each_text(('{"x":"a", "y":"b"}')::json) t1
         FULL OUTER JOIN json_each_text(('{"y":"b", "x":"a"}')::json) t2 USING (key)
    WHERE t1.value<>t2.value OR t1.key IS NULL OR t2.key IS NULL
)

请注意,仅当两个JSON值是对象(每个键的值都是字符串)的对象时,此方法才有效。

Note that this only works if the two JSON values are objects where for each key, the values are strings.

键位于 exists 内部的查询中:在该查询中,我们将第一个JSON对象中的所有键与第二个JSON对象中的对应键进行匹配。然后,仅保留与以下两种情况之一相对应的行:

The key is in the query inside the exists: In that query we match all keys from the first JSON objects with the corresponding keys in the second JSON object. Then we keep only the rows that correspond to one of the following two cases:


  • 两个JSON对象中都存在一个键,但是对应的值是

  • 一个键仅存在于两个JSON对象之一中,而另一个不存在

这是唯一见证两个对象不平等的情况,因此我们用 NOT不存在(...)包裹所有内容,即如果我们

These are the only cases that "witness" the inequality of the two objects, hence we wrap everything with a NOT exists(...), i.e. the objects are equal if we didn't find any witnesses of inequality.

如果需要支持其他类型的JSON值(例如数组,嵌套对象等),则可以编写 plpgsql 函数基于上述想法。

If you need to support other types of JSON values (e.g. arrays, nested objects, etc), you can write a plpgsql function based on the above idea.

这篇关于PostgreSQL:比较JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-26 02:44
查看更多