Postgresql数据类型-json/jsonb类型

PostgreSQL不只是一个关系型数据库,同时它还支持非关系数据类型json (JavaScript Object Notation), json属于重量级的非常规数据类型,本节将介绍json类型、json与jsonb差异、json与jsonb操作符和函数,以及jsonb键值的追加、删除、更新。

json类型简介

PostgreSQL早在9.2版本已经提供了json类型,并且随着大版本的演进,PostgreSQL对json的支持趋于完善,例如提供更多的json函数和操作符方便应用开发,一个简单的json类型例子如下:

        mydb=> SELECT '{"a":1, "b":2}'::json;
                json
        ---------------
            {"a":1, "b":2}

为了更好地演示json类型,接下来创建一张表,如下所示:

        mydb=> CREATE TABLE test_json1 (id serial primary key, name json);
        CREATE TABLE

以上示例定义字段name为json类型,插入表数据,如下所示:

        mydb=> INSERT INTO test_json1 (name)
        VALUES ('{"col1":1, "col2":"francs", "col3":"male"}');
        INSERT 0 1

        mydb=> INSERT INTO test_json1 (name)
        VALUES ('{"col1":2, "col2":"fp", "col3":"female"}');
        INSERT 0 1

查询表test_json1数据,如下所示:

        mydb=> SELECT * FROM test_json1;
            id |                    name
        -------+------------------------------------------
              1 | {"col1":1, "col2":"francs", "col3":"male"}
              2 | {"col1":2, "col2":"fp", "col3":"female"}

查询json数据

通过“->”操作符可以查询json数据的键值,如下所示:

        mydb=> SELECT  name -> 'col2' FROM test_json1 WHERE id=1;
            ?column?
        ----------
            "francs"
        (1 row)

如果想以文本格式返回json字段键值可以使用“->>”操作符,如下所示:

        mydb=> SELECT  name ->> 'col2' FROM test_json1 WHERE id=1;
            ?column?
        ----------
            francs
        (1 row)

jsonb与json差异

PostgreSQL支持两种JSON数据类型:json和jsonb,两种类型在使用上几乎完全相同,两者主要区别为以下:json存储格式为文本而jsonb存储格式为二进制,由于存储格式的不同使得两种json数据类型的处理效率不一样,json类型以文本存储并且存储的内容和输入数据一样,当检索json数据时必须重新解析,而jsonb以二进制形式存储已解析好的数据,当检索jsonb数据时不需要重新解析,因此json写入比jsonb快,但检索比jsonb慢,后面会通过测试验证两者读写性能的差异。除了上述介绍的区别之外,json与jsonb在使用过程中还存在差异,例如jsonb输出的键的顺序和输入不一样,如下所示:

        mydb=> SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::jsonb;
                jsonb
        --------------------------------------------------
            {"bar": "baz", "active": false, "balance": 7.77}
        (1 row)

而json的输出键的顺序和输入完全一样,如下所示:

        mydb=> SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::json;
                json
        -------------------------------------------------
            {"bar": "baz", "balance": 7.77, "active":false}
        (1 row)

另外,jsonb类型会去掉输入数据中键值的空格,如下所示:

        mydb=> SELECT ' {"id":1,    "name":"francs"}'::jsonb;
                jsonb
        -----------------------------
            {"id": 1, "name": "francs"}
        (1 row)

上例中id键与name键输入时是有空格的,输出显示空格键被删除,而json的输出和输入一样,不会删掉空格键:

        mydb=> SELECT ' {"id":1,    "name":"francs"}'::json;
                    json
        -------------------------------
                {"id":1,    "name":"francs"}
        (1 row)

另外,jsonb会删除重复的键,仅保留最后一个,如下所示:

        mydb=> SELECT ' {"id":1,
        "name":"francs",
        "remark":"a good guy! ",
        "name":"test"
        }'::jsonb;
                        jsonb
        ----------------------------------------------------
            {"id": 1, "name": "test", "remark": "a good guy! "}
        (1 row)

上面name键重复,仅保留最后一个name键的值,而json数据类型会保留重复的键值。在大多数应用场景下建议使用jsonb,除非有特殊的需求,比如对json的键顺序有特殊的要求。

jsonb与json操作符

以文本格式返回json类型的字段键值可以使用“->>”操作符,如下所示:

        mydb=> SELECT  name ->> 'col2' FROM test_json1 WHERE id=1;
            ?column?
        ----------
            francs
        (1 row)

字符串是否作为顶层键值,如下所示:

        mydb=> SELECT '{"a":1, "b":2}'::jsonb ? 'a';
            ?column?
        ----------
            t
        (1 row)

删除json数据的键/值,如下所示:

        mydb=> SELECT '{"a":1, "b":2}'::jsonb - 'a';
            ?column?
        ----------
            {"b": 2}
        (1 row)

jsonb与json函数

json与jsonb相关的函数非常丰富,下面举例说明。扩展最外层的json对象成为一组键/值结果集,如下所示:

        mydb=> SELECT * FROM json_each('{"a":"foo", "b":"bar"}');
            key | value
        --------+-------
            a   | "foo"
            b   | "bar"
        (2 rows)

以文本形式返回结果,如下所示:

        mydb=> SELECT * FROM json_each_text('{"a":"foo", "b":"bar"}');
            key | value
        --------+-------
            a   | foo
            b   | bar
        (2 rows)

一个非常重要的函数为row_to_json()函数,能够将行作为json对象返回,此函数常用来生成json测试数据,比如将一个普通表转换成json类型表,代码如下所示:

        mydb=> SELECT * FROM test_copy WHERE id=1;
            id | name
        -------+------
              1 | a
        (1 row)
        mydb=> SELECT row_to_json(test_copy) FROM test_copy WHERE id=1;
            row_to_json
        ---------------------
            {"id":1, "name":"a"}
        (1 row)

返回最外层的json对象中的键的集合,如下所示:

        mydb=> SELECT * FROM json_object_keys('{"a":"foo", "b":"bar"}');
            json_object_keys
        ------------------
            a
            b
        (2 rows)

jsonb键/值的追加、删除、更新

jsonb键/值追加可通过“||”操作符,例如增加sex键/值,如下所示:

        mydb=> SELECT '{"name":"francs", "age":"31"}'::jsonb ||
        '{"sex":"male"}'::jsonb;
                            ?column?
        ------------------------------------------------
            {"age": "31", "sex": "male", "name": "francs"}
        (1 row)

jsonb键/值的删除有两种方法,一种是通过操作符“-”删除,另一种通过操作符“#-”删除指定键/值,通过操作符“-”删除键/值的代码如下所示:

        mydb=> SELECT '{"name": "James", "email": "james@localhost"}'::jsonb
            - 'email';
            ?column?
        -------------------
            {"name": "James"}
        (1 row)

        mydb=> SELECT '["red", "green", "blue"]'::jsonb -0;
            ?column?
        -------------------
            ["green", "blue"]

第二种方法是通过操作符“#-”删除指定键/值,通常用于有嵌套json数据删除的场景,如下代码删除嵌套contact中的fax键/值:

        mydb=>  SELECT  '{"name":  "James",  "contact":  {"phone":  "01234  567890",  "fax":
            "01987543210"}}'::jsonb #- '{contact, fax}'::text[];
                                  ?column?
        ---------------------------------------------------------
            {"name": "James", "contact": {"phone": "01234567890"}}
        (1 row)

删除嵌套aliases中的位置为1的键/值,如下所示:

        mydb=> SELECT '{"name": "James", "aliases": ["Jamie", "The Jamester", "J Man"]}'::jsonb
            #- '{aliases,1}'::text[];
                              ?column?
        --------------------------------------------------
            {"name": "James", "aliases": ["Jamie", "J Man"]}
        (1 row)

键/值的更新也有两种方式,第一种方式为“||”操作符,“||”操作符可以连接json键,也可覆盖重复的键值,如下代码修改age键的值:

        mydb=> SELECT '{"name":"francs", "age":"31"}'::jsonb ||
        '{"age":"32"}'::jsonb;
                    ?column?
        ---------------------------------
            {"age": "32", "name": "francs"}
        (1 row)

第二种方式是通过jsonb_set函数,语法如下:

        jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing boolean])

target指源jsonb数据,path指路径,new_value指更新后的键值,create_missing值为true表示如果键不存在则添加,create_missing值为false表示如果键不存在则不添加,示例如下:

        mydb=> SELECT jsonb_set('{"name":"francs", "age":"31"}'::jsonb, '{age}', '"32"'::jsonb, false);
                    jsonb_set
        ---------------------------------
            {"age": "32", "name": "francs"}
        (1 row)
        mydb=> SELECT jsonb_set('{"name":"francs", "age":"31"}'::jsonb, '{sex}', '"male"'::jsonb, true);
                            jsonb_set
        ------------------------------------------------
            {"age": "31", "sex": "male", "name": "francs"}
        (1 row)

你可能感兴趣的:(数据处理,postgresql,json,数据库)