{"kind": "type", "slug": "jsonpath", "name": "jsonpath", "major": "18", "snapshot": {"casts": [], "facts": [{"label": "目录名称", "value": "pg_catalog.jsonpath"}, {"label": "类型 OID", "value": "4072"}, {"label": "类型种类", "value": "基础类型"}, {"label": "声明长度", "value": "变长（varlena）"}, {"label": "存储策略", "value": "扩展"}, {"label": "输入函数", "value": "jsonpath_in"}, {"label": "输出函数", "value": "jsonpath_out"}], "ranges": [], "aliases": [], "catalog": {"oid": "4072", "descr": "JSON path", "typacl": "_null_", "typlen": "-1", "typelem": "0", "typname": "jsonpath", "typsend": "jsonpath_send", "typtype": "b", "typalign": "i", "typarray": "0", "typbyval": "f", "typdelim": "','", "typinput": "jsonpath_in", "typmodin": "-", "typndims": "0", "typowner": "POSTGRES", "typrelid": "0", "typmodout": "-", "typoutput": "jsonpath_out", "typtypmod": "-1", "typanalyze": "-", "typdefault": "_null_", "typnotnull": "f", "typreceive": "jsonpath_recv", "typstorage": "x", "typbasetype": "0", "typcategory": "U", "typcollation": "0", "typisdefined": "t", "typnamespace": "pg_catalog", "typsubscript": "-", "typdefaultbin": "_null_", "array_type_oid": "4073", "typispreferred": "f", "array_type_name": "_jsonpath"}, "related": [{"url": "/wiki/catalog/pg_type/?v=18", "label": "pg_type 系统目录"}, {"url": "/wiki/catalog/pg_cast/?v=18", "label": "pg_cast 系统目录"}, {"url": "/wiki/catalog/pg_operator/?v=18", "label": "pg_operator 系统目录"}, {"url": "/wiki/catalog/pg_opclass/?v=18", "label": "pg_opclass 系统目录"}, {"url": "/wiki/type/arrays/?v=18", "label": "数组"}], "release": {"ref": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "label": "18.6", "major": "18", "channel": "stable", "revision": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f", "source_files": {"doc/src/sgml/datatype.sgml": "86328daa77e20d81d222376ec0306d9841a17104e436c08d138eb763aefb3700", "src/include/catalog/pg_am.h": "3426799df799f32163fcc0765f43dbdb5e88e626acf31284fef9fc6014b69d8e", "src/include/catalog/pg_am.dat": "b3cb86b102a42fb0024cbd99779c9897afb40d12a71f5cc5a0e5aee7ff2f9969", "src/include/catalog/pg_cast.h": "de585c7df687d698e7d1d100dce8a794ac9da52414ea48169191019178c8f053", "src/include/catalog/pg_proc.h": "f7d59f07c5b95e2f3c7141762a0f576e8a3af7581ba54c27537f4d500472bea5", "src/include/catalog/pg_type.h": "8fb198749fd82b6c1818a3c18455f226f66116fcfeb3d4959c65ce3fda22802e", "src/include/catalog/pg_range.h": "45546d952b5181f989bd9234721897fc2b37005c8e49ce2ddc156f26974c3ca4", "src/include/catalog/pg_cast.dat": "97911281ca2c81917394ccb2ec13367e37c6801fd461d5e1a3d2f28b911b46b2", "src/include/catalog/pg_proc.dat": "1f934ce80d460159dda137714374a35f9896315ea2476709cbb4da13b38ef95a", "src/include/catalog/pg_type.dat": "5f5887b75677cba2d4a1a0cfeb355df5ed91f85d385fac88bd8d7c605b3578f9", "src/include/catalog/pg_opclass.h": "9c218537806c8ef0398302faaca7f91315dfc1198c48706cebffb479b68defaf", "src/include/catalog/pg_range.dat": "5c2271f8e89e9378d1887204e5785060b77405b5f0ff3e6c719250c9c1dcfcc4", "src/include/catalog/pg_operator.h": "621b18cfffe102413d79b746ce7a10f77fc60fdd097bac34c22b31070d3ee3c4", "src/include/catalog/pg_opfamily.h": "e1f5fc8aebd3042df847455bf66bf755f768c2aa8a9b03d22f7ec8563eba59c0", "src/include/catalog/pg_opclass.dat": "4ee7d3619a6aa106e1c0db55de903931c7d11b1c60ba053a022519c55f8ee668", "src/include/catalog/pg_operator.dat": "5d35b9b2ef5f9797cc815263927ef8a12367fedace53e828b4e8b320e2a7f703", "src/include/catalog/pg_opfamily.dat": "3b694879027b858f2ecf1fa1152b7e30c6e15a216ba99c2384291c30e9d52311"}, "manual_sha256": {"arrays.html": "0e1d5c5a7b4a949d4439995f44f74ad4264e050d16eb9ad2a850fbaee04032df", "domains.html": "82d486973ccc35d14276627a67ac76b434452f23f9ed4d8aa3fbb01fdf285fc2", "datatype.html": "e581f67c74e42006289638c8659e9b338adbfd7f068bd8bf2b3be3880fcd2254", "rowtypes.html": "74f99e029c3a9edfd3e18810ba3c8cb66d3aada91eb67b86476560871e6617e9", "rangetypes.html": "e4960abc7ce8e51d794f94f1e57b099d30b7f75dd7f2b23a960eef91f6291c33", "datatype-bit.html": "c49124aad561636c18080b9e09572fde7785a6b9eae86f5a33283f0fd6774c37", "datatype-oid.html": "8b3360302225f08ae72716ce1804596de95b568e5d31f788cb4597427b28cc38", "datatype-xml.html": "061fc2295b7b69be704f0a741b8decd10ad721059f871fb0243c669bb54d7822", "datatype-enum.html": "cab38e53222e30cc94b24de4b33634fd22d7c93f58ebcf35f646c9b8da78fae8", "datatype-json.html": "650162a05b660146b500a205d523374d00aee117a6a6240d30262be51b6e33e5", "datatype-uuid.html": "292b307b3223c6182bdba687e7f69e6dca9038430143ad79d56327f6ed4c3246", "datatype-money.html": "8b29c14b90679683ac5c472b59a0a7e2853f32cc7db43fab417b2697a6879964", "functions-info.html": "78ac80bf81da2e4f4a33f3b850faa86f0f58ec54a083d6c31da557907de0df87", "catalog-pg-type.html": "ea9c9313bab8e92a7da18ebc50c7ff1f908dd80999a7e0ca3bbc82ba626c58d4", "datatype-binary.html": "0c03ec47b76e37888a3da7f5dcfd340128a5d356642a85185cc9ebe17856a904", "datatype-pg-lsn.html": "339172f5107cc7eb7139bec911277647219e92a532cebd0f3da0a5dacf8195af", "datatype-pseudo.html": "c7cf0b8214304bd8702c95f2142671ae5f0d631f83717f9c07d9e1f2579961b4", "datatype-boolean.html": "b633f663e6c8276e7056287640c413aa79dbc15d5353cee0d41653d58d376956", "datatype-numeric.html": "b74619f7ac2f1ca9f85c48073df78c33dd30e464e61baba6008634534edcb500", "sql-createdomain.html": "e94f927196de1b0ea1ce35cd4603c1f6f544439adcc0edf1c4222358e832245b", "datatype-datetime.html": "e366275d8b13845bfa4ef0d68faa093e5f3ecb708a1ec870cbcbf7e425b85699", "datatype-character.html": "c73eebe413ea709a7792e4cfc3cfe9fb68cb496ebe83c3ebaa9d09f8c40d0f73", "datatype-geometric.html": "0eb3053cfe7d6b0a4b5592c5d7af8d97cae527e87f063c5793413bcba5c14cd9", "datatype-net-types.html": "96846e641cc37727ddcd8b8a1aa0dbe33cd9787760a2b4efb0dcb9403d5be63f", "datatype-textsearch.html": "4b15e05be8b49a71b28aea22f2c46d0dbf639a91e7b4fe129a4c737c6daad47c"}, "source_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, "sources": [{"url": "https://pg.center/docs/18/datatype-json.html", "path": "datatype-json.html", "label": "PostgreSQL 18 English manual", "sha256": "650162a05b660146b500a205d523374d00aee117a6a6240d30262be51b6e33e5", "language": "en", "original_url": "/docs/18/datatype-json.html"}, {"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "label": "Matching PostgreSQL source archive", "sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}], "coverage": "source inventory; exact declared input types for operator classes", "sections": [], "operators": [{"oid": "4012", "descr": "jsonpath exists", "oprcom": "0", "oprcode": "jsonb_path_exists_opr(jsonb,jsonpath)", "oprjoin": "matchingjoinsel", "oprkind": "b", "oprleft": "jsonb", "oprname": "@?", "oprrest": "matchingsel", "oprowner": "POSTGRES", "oprright": "jsonpath", "oprnegate": "0", "oprresult": "bool", "oprcanhash": "f", "oprcanmerge": "f", "oprnamespace": "pg_catalog"}, {"oid": "4013", "descr": "jsonpath match", "oprcom": "0", "oprcode": "jsonb_path_match_opr(jsonb,jsonpath)", "oprjoin": "matchingjoinsel", "oprkind": "b", "oprleft": "jsonb", "oprname": "@@", "oprrest": "matchingsel", "oprowner": "POSTGRES", "oprright": "jsonpath", "oprnegate": "0", "oprresult": "bool", "oprcanhash": "f", "oprcanmerge": "f", "oprnamespace": "pg_catalog"}], "signature": "jsonpath", "description": ["JSON 路径"], "manual_html": "<div class=\"sect1\" id=\"DATATYPE-JSON\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\" lang=\"zh\">\n<div>\n<div>\n<h2 class=\"title\" style=\"clear: both\">8.14. <acronym class=\"acronym\">JSON</acronym> 类型 </h2>\n</div>\n</div>\n</h2>\n</div>\n</div>\n</div>\n<p lang=\"zh\">JSON 数据类型用于存储 JSON（JavaScript Object Notation）数据，如 <a class=\"ulink\" href=\"https://datatracker.ietf.org/doc/html/rfc7159\" target=\"_top\">RFC 7159</a> 所定义。这类数据也可以存储为 <code class=\"type\">text</code>，但 JSON 数据类型的优势在于会强制每个存储值都符合 JSON 规则。此外，对于存储在这些数据类型中的数据，还提供了各种 JSON 专用的函数和操作符；见<a class=\"xref\" href=\"/docs/18/functions-json.html\" title=\"9.16. JSON 函数和操作符\">第 9.16 节</a>。</p>\n<p lang=\"zh\"><span class=\"productname\">PostgreSQL</span> 提供两种用于存储 JSON 数据的类型：<code class=\"type\">json</code> 和 <code class=\"type\">jsonb</code>。为了为这些数据类型实现高效的查询机制，<span class=\"productname\">PostgreSQL</span> 还提供了 <code class=\"type\">jsonpath</code> 数据类型，其说明见<a class=\"xref\" href=\"/docs/18/datatype-json.html#DATATYPE-JSONPATH\" title=\"8.14.7. jsonpath 类型\">第 8.14.7 节</a>。</p>\n<p lang=\"zh\"><code class=\"type\">json</code> 和 <code class=\"type\">jsonb</code> 数据类型接收的输入值集合<span class=\"emphasis\"><em>几乎</em></span>完全相同。主要的实际区别在于效率。<code class=\"type\">json</code> 数据类型存储输入文本的精确副本，因此处理函数在每次执行时都必须重新解析；而 <code class=\"type\">jsonb</code> 数据则以分解后的二进制格式存储，由于增加了转换开销，输入时会稍慢一些，但处理起来会显著更快，因为不需要重新解析。<code class=\"type\">jsonb</code> 还支持索引，这可能是一个显著优势。</p>\n<p lang=\"zh\">由于 <code class=\"type\">json</code> 类型存储的是输入文本的精确副本，因此它会保留词元之间在语义上无关紧要的空白，以及 JSON 对象内部键的顺序。此外，如果值中的某个 JSON 对象包含同一个键多次，所有键/值对都会被保留下来（处理函数会将最后一个值视为生效值）。相比之下，<code class=\"type\">jsonb</code> 不保留空白，不保留对象键的顺序，也不保留重复的对象键。如果输入中指定了重复的键，则只保留最后一个值。</p>\n<p lang=\"zh\">一般而言，大多数应用都应优先将 JSON 数据存储为 <code class=\"type\">jsonb</code>，除非存在相当特殊的需求，例如遗留系统对对象键顺序的假设。</p>\n<p lang=\"zh\"><acronym class=\"acronym\">RFC</acronym> 7159 规定 JSON 字符串应使用 UTF8 编码。因此，除非数据库编码是 UTF8，否则 JSON 类型不可能严格符合 JSON 规范。尝试直接包含数据库编码无法表示的字符会失败；反过来，数据库编码可以表示但 UTF8 不能表示的字符则会被允许。</p>\n<p lang=\"zh\"><acronym class=\"acronym\">RFC</acronym> 7159 允许 JSON 字符串包含以 <code class=\"literal\">\\u<em class=\"replaceable\"><code>XXXX</code></em></code> 表示的 Unicode 转义序列。在 <code class=\"type\">json</code> 类型的输入函数中，无论数据库编码为何，都允许 Unicode 转义，并且只检查其语法是否正确（即 <code class=\"literal\">\\u</code> 后面是否跟着四个十六进制数字）。但是，<code class=\"type\">jsonb</code> 的输入函数更严格：它不允许对数据库编码无法表示的字符使用 Unicode 转义。<code class=\"type\">jsonb</code> 类型还会拒绝 <code class=\"literal\">\\u0000</code>（因为 <span class=\"productname\">PostgreSQL</span> 的 <code class=\"type\">text</code> 类型无法表示它），并且要求任何使用 Unicode 代理对来表示位于 Unicode 基本多文种平面之外字符的写法都必须正确。合法的 Unicode 转义会在存储时转换为等效的单个字符；这也包括把代理对折叠为一个字符。</p>\n<div class=\"note\">\n<h3 class=\"title\" lang=\"zh\">注意</h3>\n<p lang=\"zh\"><a class=\"xref\" href=\"/docs/18/functions-json.html\" title=\"9.16. JSON 函数和操作符\">第 9.16 节</a>中描述的很多 JSON 处理函数都会把 Unicode 转义转换为普通字符，因此即使它们的输入是 <code class=\"type\">json</code> 而不是 <code class=\"type\">jsonb</code>，也会抛出前面刚描述过的同类错误。<code class=\"type\">json</code> 的输入函数不做这些检查，可以视为一种历史遗留行为；不过，它确实允许在不支持所表示字符的数据库编码中，简单地存储（而不做处理）带有 JSON Unicode 转义的内容。</p>\n</div>\n<p lang=\"zh\">将 JSON 文本输入转换为 jsonb 时，RFC 7159 描述的原始类型实际上会映射为 PostgreSQL 原生类型，见表 8.23。因此，底层类型的表示范围会对合法 jsonb 数据施加一些轻微的附加限制，这些限制不适用于 json，也不适用于抽象意义上的 JSON。特别是，jsonb 会拒绝超出 PostgreSQL numeric 范围的数值，而 json 不会。RFC 7159 允许此类由实现定义的限制。不过，实际中其他实现更容易遇到这类问题，因为它们通常用 IEEE 754 双精度浮点数表示 JSON 的 number 原始类型，RFC 7159 也明确预见并允许了这种做法。与这类系统使用 JSON 交换数据时，应考虑相对于 PostgreSQL 原始存储值丢失数值精度的风险。</p>\n<p lang=\"zh\">另一方面，正如表中所指出的那样，JSON 基本类型的输入格式还有一些轻微限制，而对应的 <span class=\"productname\">PostgreSQL</span> 类型并没有这些限制。</p>\n<div class=\"table\" id=\"JSON-TYPE-MAPPING-TABLE\">\n<p class=\"title\" lang=\"zh\"><strong>表 8.23. JSON 基本类型及其对应的 <span class=\"productname\">PostgreSQL</span> 类型</strong></p>\n<div class=\"table-contents\">\n<table class=\"table\">\n<thead>\n<tr>\n<th lang=\"zh\">JSON 基本类型</th>\n<th lang=\"zh\"><span class=\"productname\">PostgreSQL</span> 类型</th>\n<th lang=\"zh\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code class=\"type\">string</code></td>\n<td lang=\"zh\">文本</td>\n<td lang=\"zh\">不允许 <code class=\"literal\">\\u0000</code>，也不允许表示数据库编码中不可用字符的 Unicode 转义</td>\n</tr>\n<tr>\n<td><code class=\"type\">number</code></td>\n<td><code class=\"type\">numeric</code></td>\n<td lang=\"zh\">不允许 <code class=\"literal\">NaN</code> 和 <code class=\"literal\">infinity</code> 值</td>\n</tr>\n<tr>\n<td><code class=\"type\">boolean</code></td>\n<td><code class=\"type\">boolean</code></td>\n<td lang=\"zh\">只接受小写拼写 <code class=\"literal\">true</code> 和 <code class=\"literal\">false</code></td>\n</tr>\n<tr>\n<td><code class=\"type\">null</code></td>\n<td lang=\"zh\">（无）</td>\n<td lang=\"zh\">SQL <code class=\"literal\">NULL</code> 是不同的概念</td>\n</tr>\n</tbody>\n</table>\n</div>\n</div><br class=\"table-break\"/>\n<div class=\"sect2\" id=\"JSON-KEYS-ELEMENTS\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/datatype-json.html#JSON-KEYS-ELEMENTS\">8.14.1. JSON 输入和输出语法</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">JSON 数据类型的输入／输出语法遵循 RFC 7159。</p>\n<p lang=\"zh\">以下都是有效的 <code class=\"type\">json</code>（或 <code class=\"type\">jsonb</code>）表达式：</p>\n<pre class=\"programlisting\">-- Simple scalar/primitive value\n-- Primitive values can be numbers, quoted strings, true, false, or null\nSELECT '5'::json;\n\n-- Array of zero or more elements (elements need not be of same type)\nSELECT '[1, 2, \"foo\", null]'::json;\n\n-- Object containing pairs of keys and values\n-- Note that object keys must always be quoted strings\nSELECT '{\"bar\": \"baz\", \"balance\": 7.77, \"active\": false}'::json;\n\n-- Arrays and objects can be nested arbitrarily\nSELECT '{\"foo\": [true, \"bar\"], \"tags\": {\"a\": 1, \"b\": null}}'::json;\n</pre>\n<p lang=\"zh\">如前所述，当一个 JSON 值被输入后又在不进行任何额外处理的情况下输出时，<code class=\"type\">json</code> 会输出与输入完全相同的文本，而 <code class=\"type\">jsonb</code> 不会保留诸如空白这类语义上无关紧要的细节。例如，请注意这里的差异：</p>\n<pre class=\"programlisting\">SELECT '{\"bar\": \"baz\", \"balance\": 7.77, \"active\":false}'::json;\n                      json\n-------------------------------------------------\n {\"bar\": \"baz\", \"balance\": 7.77, \"active\":false}\n(1 row)\n\nSELECT '{\"bar\": \"baz\", \"balance\": 7.77, \"active\":false}'::jsonb;\n                      jsonb\n--------------------------------------------------\n {\"bar\": \"baz\", \"active\": false, \"balance\": 7.77}\n(1 row)\n</pre>\n<p lang=\"zh\">一个值得注意的语义无关细节是，在 <code class=\"type\">jsonb</code> 中，数字会按照底层 <code class=\"type\">numeric</code> 类型的行为输出。在实践中，这意味着使用 <code class=\"literal\">E</code> 记数法输入的数字在输出时将不再使用这种写法，例如：</p>\n<pre class=\"programlisting\">SELECT '{\"reading\": 1.230e-5}'::json, '{\"reading\": 1.230e-5}'::jsonb;\n         json          |          jsonb\n-----------------------+-------------------------\n {\"reading\": 1.230e-5} | {\"reading\": 0.00001230}\n(1 row)\n</pre>\n<p lang=\"zh\">不过，正如这个例子所示，<code class=\"type\">jsonb</code> 会保留小数部分末尾的零，尽管对于等值检查之类的用途来说，这些零在语义上并不重要。</p>\n<p lang=\"zh\">关于可用于构造和处理 JSON 值的内置函数和操作符列表，见<a class=\"xref\" href=\"/docs/18/functions-json.html\" title=\"9.16. JSON 函数和操作符\">第 9.16 节</a>。</p>\n</div>\n<div class=\"sect2\" id=\"JSON-DOC-DESIGN\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/datatype-json.html#JSON-DOC-DESIGN\">8.14.2. 设计 JSON 文档</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">以 JSON 形式表示数据，可能比传统的关系数据模型灵活得多，这在需求变化较大的环境中尤其有吸引力。这两种方法完全可能在同一个应用中共存并互为补充。但是，即使对于追求最大灵活性的应用，也仍然建议 JSON 文档拥有某种相对固定的结构。这种结构通常并不受强制约束（尽管也可以用声明式方式强制某些业务规则），但具有可预测的结构会让编写查询更容易，从而能够有效地汇总表中一组<span class=\"quote\">“<span class=\"quote\">文档</span>”</span>（数据项）。</p>\n<p lang=\"zh\">当 JSON 数据存储在表中时，它与任何其他数据类型一样，都要面对相同的并发控制考量。虽然存储大型文档是可行的，但要记住，任何更新都会在整行上获取一个行级锁。应考虑将 JSON 文档限制在可管理的大小，以减少更新事务之间的锁争用。理想情况下，每个 JSON 文档都应表示一个原子数据项，根据业务规则，无法再合理地将它细分为更小且可独立修改的数据项。</p>\n</div>\n<div class=\"sect2\" id=\"JSON-CONTAINMENT\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/datatype-json.html#JSON-CONTAINMENT\">8.14.3. <code class=\"type\">jsonb</code> 包含与存在</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">测试<em class=\"firstterm\">包含</em>是 <code class=\"type\">jsonb</code> 的一项重要能力。对于 <code class=\"type\">json</code> 类型，则没有与之对应的一组功能。包含测试用于检查一个 <code class=\"type\">jsonb</code> 文档中是否包含另一个文档。除特别说明外，下面这些示例都返回真：</p>\n<pre class=\"programlisting\">-- Simple scalar/primitive values contain only the identical value:\nSELECT '\"foo\"'::jsonb @&gt; '\"foo\"'::jsonb;\n\n-- The array on the right side is contained within the one on the left:\nSELECT '[1, 2, 3]'::jsonb @&gt; '[1, 3]'::jsonb;\n\n-- Order of array elements is not significant, so this is also true:\nSELECT '[1, 2, 3]'::jsonb @&gt; '[3, 1]'::jsonb;\n\n-- Duplicate array elements don't matter either:\nSELECT '[1, 2, 3]'::jsonb @&gt; '[1, 2, 2]'::jsonb;\n\n-- The object with a single pair on the right side is contained\n-- within the object on the left side:\nSELECT '{\"product\": \"PostgreSQL\", \"version\": 9.4, \"jsonb\": true}'::jsonb @&gt; '{\"version\": 9.4}'::jsonb;\n\n-- The array on the right side is <span class=\"emphasis\"><strong>not</strong></span> considered contained within the\n-- array on the left, even though a similar array is nested within it:\nSELECT '[1, 2, [1, 3]]'::jsonb @&gt; '[1, 3]'::jsonb;  -- yields false\n\n-- But with a layer of nesting, it is contained:\nSELECT '[1, 2, [1, 3]]'::jsonb @&gt; '[[1, 3]]'::jsonb;\n\n-- Similarly, containment is not reported here:\nSELECT '{\"foo\": {\"bar\": \"baz\"}}'::jsonb @&gt; '{\"bar\": \"baz\"}'::jsonb;  -- yields false\n\n-- A top-level key and an empty object is contained:\nSELECT '{\"foo\": {\"bar\": \"baz\"}}'::jsonb @&gt; '{\"foo\": {}}'::jsonb;\n</pre>\n<p lang=\"zh\">一般原则是，被包含对象在结构和数据内容上都必须与包含对象匹配；必要时，可以从包含对象中丢弃某些不匹配的数组元素或对象键/值对后再进行这种匹配。但要记住，在进行包含匹配时，数组元素的顺序并不重要，重复的数组元素实际上也只会被考虑一次。</p>\n<p lang=\"zh\">对于结构必须匹配这一一般原则，有一个特殊例外：数组可以包含一个基本值：</p>\n<pre class=\"programlisting\">-- This array contains the primitive string value:\nSELECT '[\"foo\", \"bar\"]'::jsonb @&gt; '\"bar\"'::jsonb;\n\n-- This exception is not reciprocal -- non-containment is reported here:\nSELECT '\"bar\"'::jsonb @&gt; '[\"bar\"]'::jsonb;  -- yields false\n</pre>\n<p lang=\"zh\"><code class=\"type\">jsonb</code> 还有一个<em class=\"firstterm\">存在</em>操作符，它可看作包含的一种变体：它测试某个字符串（以 <code class=\"type\">text</code> 值给出）是否在 <code class=\"type\">jsonb</code> 值的顶层作为对象键或数组元素出现。除特别说明外，下面这些示例都返回真：</p>\n<pre class=\"programlisting\">-- String exists as array element:\nSELECT '[\"foo\", \"bar\", \"baz\"]'::jsonb ? 'bar';\n\n-- String exists as object key:\nSELECT '{\"foo\": \"bar\"}'::jsonb ? 'foo';\n\n-- Object values are not considered:\nSELECT '{\"foo\": \"bar\"}'::jsonb ? 'bar';  -- yields false\n\n-- As with containment, existence must match at the top level:\nSELECT '{\"foo\": {\"bar\": \"baz\"}}'::jsonb ? 'bar'; -- yields false\n\n-- A string is considered to exist if it matches a primitive JSON string:\nSELECT '\"foo\"'::jsonb ? 'foo';\n</pre>\n<p lang=\"zh\">当涉及很多键或元素时，JSON 对象比数组更适合用于测试包含或存在，因为对象与数组不同，内部已针对搜索做了优化，不需要进行线性搜索。</p>\n<div class=\"tip\">\n<h3 class=\"title\" lang=\"zh\">提示</h3>\n<p lang=\"zh\">由于 JSON 包含是嵌套的，因此适当的查询可以跳过对子对象的显式选择。例如，假设我们有一个 <code class=\"structfield\">doc</code> 列，其顶层是对象，而且大多数对象都带有 <code class=\"literal\">tags</code> 字段，该字段中包含子对象数组。下面这个查询会找出同时出现包含 <code class=\"literal\">\"term\":\"paris\"</code> 的子对象和包含 <code class=\"literal\">\"term\":\"food\"</code> 的子对象的项，同时忽略 <code class=\"literal\">tags</code> 数组之外的任何此类键：</p>\n<pre class=\"programlisting\">SELECT doc-&gt;'site_name' FROM websites\n  WHERE doc @&gt; '{\"tags\":[{\"term\":\"paris\"}, {\"term\":\"food\"}]}';\n</pre>\n<p lang=\"zh\">例如，也可以用下面的写法完成同样的事情：</p>\n<pre class=\"programlisting\">SELECT doc-&gt;'site_name' FROM websites\n  WHERE doc-&gt;'tags' @&gt; '[{\"term\":\"paris\"}, {\"term\":\"food\"}]';\n</pre>\n<p lang=\"zh\">但这种做法的灵活性较差，而且通常效率也更低。</p>\n<p lang=\"zh\">另一方面，JSON 的存在操作符并不是嵌套的：它只会在 JSON 值的顶层查找指定的键或数组元素。</p>\n</div>\n<p lang=\"zh\">各种包含和存在操作符，以及所有其他 JSON 操作符和函数，均见<a class=\"xref\" href=\"/docs/18/functions-json.html\" title=\"9.16. JSON 函数和操作符\">第 9.16 节</a>。</p>\n</div>\n<div class=\"sect2\" id=\"JSON-INDEXING\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/datatype-json.html#JSON-INDEXING\">8.14.4. <code class=\"type\">jsonb</code> 索引</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">GIN 索引可用于高效搜索大量 <code class=\"type\">jsonb</code> 文档（数据项）中出现的键或键/值对。提供了两种 GIN <span class=\"quote\">“<span class=\"quote\">操作符类</span>”</span>，它们在性能和灵活性之间提供不同的权衡。</p>\n<p lang=\"zh\"><code class=\"type\">jsonb</code> 的默认 GIN 操作符类支持使用键存在操作符 <code class=\"literal\">?</code>、<code class=\"literal\">?|</code> 和 <code class=\"literal\">?&amp;</code>，包含操作符 <code class=\"literal\">@&gt;</code>，以及 <code class=\"type\">jsonpath</code> 匹配操作符 <code class=\"literal\">@?</code> 和 <code class=\"literal\">@@</code> 的查询。（关于这些操作符所实现语义的细节，见<a class=\"xref\" href=\"/docs/18/functions-json.html#FUNCTIONS-JSONB-OP-TABLE\" title=\"表 9.48. 附加的 jsonb 操作符\">表 9.48</a>。）使用此操作符类创建索引的例子如下：</p>\n<pre class=\"programlisting\">CREATE INDEX idxgin ON api USING GIN (jdoc);\n</pre>\n<p lang=\"zh\">非默认的 GIN 操作符类 <code class=\"literal\">jsonb_path_ops</code> 不支持键存在操作符，但支持 <code class=\"literal\">@&gt;</code>、<code class=\"literal\">@?</code> 和 <code class=\"literal\">@@</code>。使用此操作符类创建索引的例子如下：</p>\n<pre class=\"programlisting\">CREATE INDEX idxginp ON api USING GIN (jdoc jsonb_path_ops);\n</pre>\n<p lang=\"zh\">假设有一个表，用于存储从第三方 Web 服务检索到的 JSON 文档，而且该服务的模式定义已有文档说明。一个典型文档如下：</p>\n<pre class=\"programlisting\">{\n    \"guid\": \"9c36adc1-7fb5-4d5b-83b4-90356a46061a\",\n    \"name\": \"Angela Barton\",\n    \"is_active\": true,\n    \"company\": \"Magnafone\",\n    \"address\": \"178 Howard Place, Gulf, Washington, 702\",\n    \"registered\": \"2009-11-07T08:53:22 +08:00\",\n    \"latitude\": 19.793713,\n    \"longitude\": 86.513373,\n    \"tags\": [\n        \"enim\",\n        \"aliquip\",\n        \"qui\"\n    ]\n}\n</pre>\n<p lang=\"zh\">将这些文档存入名为 api 的表，使用名为 jdoc 的 jsonb 列。如果在此列上创建 GIN 索引，下面这样的查询即可利用该索引：</p>\n<pre class=\"programlisting\">-- Find documents in which the key \"company\" has value \"Magnafone\"\nSELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{\"company\": \"Magnafone\"}';\n</pre>\n<p lang=\"zh\">但是，类似下面这样的查询就无法使用该索引，因为虽然操作符 <code class=\"literal\">?</code> 可索引，但它并未直接应用到被索引的列 <code class=\"structfield\">jdoc</code> 上：</p>\n<pre class=\"programlisting\">-- Find documents in which the key \"tags\" contains key or array element \"qui\"\nSELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc -&gt; 'tags' ? 'qui';\n</pre>\n<p lang=\"zh\">不过，只要适当地使用表达式索引，上述查询也可以利用索引。如果经常查询 <code class=\"literal\">\"tags\"</code> 键中的特定项，那么定义如下索引可能是值得的：</p>\n<pre class=\"programlisting\">CREATE INDEX idxgintags ON api USING GIN ((jdoc -&gt; 'tags'));\n</pre>\n<p lang=\"zh\">现在，<code class=\"literal\">WHERE</code> 子句 <code class=\"literal\">jdoc -&gt; 'tags' ? 'qui'</code> 会被识别为把可索引操作符 <code class=\"literal\">?</code> 应用于被索引表达式 <code class=\"literal\">jdoc -&gt; 'tags'</code>。（表达式索引的更多信息见<a class=\"xref\" href=\"/docs/18/indexes-expressional.html\" title=\"11.7. 表达式索引\">第 11.7 节</a>。）</p>\n<p lang=\"zh\">另一种查询方法是利用包含，例如：</p>\n<pre class=\"programlisting\">-- Find documents in which the key \"tags\" contains array element \"qui\"\nSELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{\"tags\": [\"qui\"]}';\n</pre>\n<p lang=\"zh\"><code class=\"structfield\">jdoc</code> 列上的简单 GIN 索引可以支持这个查询。但要注意，这样的索引会存储 <code class=\"structfield\">jdoc</code> 列中每个键和值的副本，而前一个例子中的表达式索引只存储 <code class=\"literal\">tags</code> 键下出现的数据。虽然简单索引方法灵活得多（因为它支持对任意键的查询），但有针对性的表达式索引通常会比简单索引更小，搜索起来也更快。</p>\n<p lang=\"zh\">GIN 索引还支持 <code class=\"literal\">@?</code> 和 <code class=\"literal\">@@</code> 操作符，它们执行 <code class=\"type\">jsonpath</code> 匹配。示例如下：</p>\n<pre class=\"programlisting\">SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @? '$.tags[*] ? (@ == \"qui\")';\n</pre>\n<pre class=\"programlisting\">SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @@ '$.tags[*] == \"qui\"';\n</pre>\n<p lang=\"zh\">对于这些运算符，GIN 索引会从 jsonpath 模式中提取 accessors_chain == constant 形式的子句，并根据其中提到的键和值进行索引搜索。访问器链可以包含 . key、[*] 和 [ index ] 访问器。jsonb_ops 运算符类还支持 .* 和 .** 访问器，而 jsonb_path_ops 运算符类不支持。</p>\n<p lang=\"zh\">虽然 <code class=\"literal\">jsonb_path_ops</code> 操作符类只支持带有 <code class=\"literal\">@&gt;</code>、<code class=\"literal\">@?</code> 和 <code class=\"literal\">@@</code> 操作符的查询，但相较于默认操作符类 <code class=\"literal\">jsonb_ops</code>，它具有显著的性能优势。<code class=\"literal\">jsonb_path_ops</code> 索引通常比相同数据上的 <code class=\"literal\">jsonb_ops</code> 索引小得多，而且搜索也更有针对性，尤其是在查询中包含数据里频繁出现的键时。因此，搜索操作通常比使用默认操作符类时性能更佳。</p>\n<p lang=\"zh\"><code class=\"literal\">jsonb_ops</code> 与 <code class=\"literal\">jsonb_path_ops</code> GIN 索引之间的技术差异在于，前者会为数据中的每个键和值分别创建独立的索引项，而后者只会为数据中的每个值创建索引项。<a class=\"footnote\" href=\"/docs/18/datatype-json.html#ftn.id-1.5.7.22.18.9.3\"><sup class=\"footnote\" id=\"id-1.5.7.22.18.9.3\">[7]</sup></a> 基本上，每个 <code class=\"literal\">jsonb_path_ops</code> 索引项都是该值连同通向该值的键一起计算出的 hash。例如，要索引 <code class=\"literal\">{\"foo\": {\"bar\": \"baz\"}}</code>，会创建一个单独的索引项，其 hash 值中同时纳入 <code class=\"literal\">foo</code>、<code class=\"literal\">bar</code> 和 <code class=\"literal\">baz</code> 这三者。因此，查找这一结构的包含查询会得到一次非常精确的索引搜索；但完全没有办法据此找出 <code class=\"literal\">foo</code> 是否作为键出现。另一方面，<code class=\"literal\">jsonb_ops</code> 索引会分别创建三个索引项来表示 <code class=\"literal\">foo</code>、<code class=\"literal\">bar</code> 和 <code class=\"literal\">baz</code>；然后为了执行包含查询，它会查找包含这三个项的行。尽管 GIN 索引可以相当高效地执行这种 AND 搜索，但它仍然会比等效的 <code class=\"literal\">jsonb_path_ops</code> 搜索更不精确、也更慢，尤其是在包含这三个索引项中任意一个的行数非常多时。</p>\n<p lang=\"zh\"><code class=\"literal\">jsonb_path_ops</code> 方法的一个缺点是，它不会为不包含任何值的 JSON 结构产生索引项，例如 <code class=\"literal\">{\"a\": {}}</code>。如果请求查找包含此类结构的文档，就需要执行一次全索引扫描，这会相当慢。因此，<code class=\"literal\">jsonb_path_ops</code> 并不适合经常执行此类搜索的应用。</p>\n<p lang=\"zh\"><code class=\"type\">jsonb</code> 还支持 <code class=\"literal\">btree</code> 和 <code class=\"literal\">hash</code> 索引。通常只有在需要检查完整 JSON 文档是否相等时，它们才有用。<code class=\"literal\">btree</code> 对 <code class=\"type\">jsonb</code> 数据项的排序顺序通常很少受到关注，但为了完整起见，其规则如下：</p>\n<pre class=\"synopsis\"><em class=\"replaceable\"><code>Object</code></em> &gt; <em class=\"replaceable\"><code>Array</code></em> &gt; <em class=\"replaceable\"><code>Boolean</code></em> &gt; <em class=\"replaceable\"><code>Number</code></em> &gt; <em class=\"replaceable\"><code>String</code></em> &gt; <em class=\"replaceable\"><code>null</code></em>\n\n<em class=\"replaceable\"><code>Object with n pairs</code></em> &gt; <em class=\"replaceable\"><code>object with n - 1 pairs</code></em>\n\n<em class=\"replaceable\"><code>Array with n elements</code></em> &gt; <em class=\"replaceable\"><code>array with n - 1 elements</code></em>\n</pre>\n<p lang=\"zh\">其中有一个例外：出于历史原因，顶层空数组的排序小于 <em class=\"replaceable\"><code>null</code></em>。如果对象所含键值对数量相同，则按如下顺序比较：</p>\n<pre class=\"synopsis\"><em class=\"replaceable\"><code>key-1</code></em>, <em class=\"replaceable\"><code>value-1</code></em>, <em class=\"replaceable\"><code>key-2</code></em> ...\n</pre>\n<p lang=\"zh\">注意，对象键按照其存储顺序进行比较；尤其是由于较短的键会先于较长的键存储，因此这可能导致一些不太直观的结果，例如：</p>\n<pre class=\"programlisting\">{ \"aa\": 1, \"c\": 1} &gt; {\"b\": 1, \"d\": 1}\n</pre>\n<p lang=\"zh\">同样，如果数组所含元素数量相同，则按如下顺序比较：</p>\n<pre class=\"synopsis\"><em class=\"replaceable\"><code>element-1</code></em>, <em class=\"replaceable\"><code>element-2</code></em> ...\n</pre>\n<p lang=\"zh\">JSON 基本值使用与底层 <span class=\"productname\">PostgreSQL</span> 数据类型相同的比较规则。字符串使用默认数据库排序规则进行比较。</p>\n</div>\n<div class=\"sect2\" id=\"JSONB-SUBSCRIPTING\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/datatype-json.html#JSONB-SUBSCRIPTING\">8.14.5. <code class=\"type\">jsonb</code> 下标</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">jsonb 支持数组风格的下标表达式，用于提取和修改元素。可以串联下标表达式访问嵌套值，规则与 jsonb_set 函数的 path 参数相同。如果 jsonb 值是数组，数值下标从零开始；负整数从数组最后一个元素起反向计数。不支持切片表达式。下标表达式的结果始终为 jsonb 类型。</p>\n<p lang=\"zh\">UPDATE 可在 SET 子句中使用下标修改 jsonb 值。对于所有受影响的值，路径中已存在的部分必须可以继续遍历。例如，只要 val、val['a'] 和 val['a']['b'] 都是对象，路径 val['a']['b']['c'] 就可一直访问到 c。如果 val['a'] 或 val['a']['b'] 尚未定义，会将其创建为空对象并按需填充。但如果 val 本身或某个中间值已定义为字符串、数字、jsonb null 等非对象值，就无法继续遍历，会报错并中止事务。</p>\n<p lang=\"zh\">下标语法示例：</p>\n<pre class=\"programlisting\">\n-- Extract object value by key\nSELECT ('{\"a\": 1}'::jsonb)['a'];\n\n-- Extract nested object value by key path\nSELECT ('{\"a\": {\"b\": {\"c\": 1}}}'::jsonb)['a']['b']['c'];\n\n-- Extract array element by index\nSELECT ('[1, \"2\", null]'::jsonb)[1];\n\n-- Update object value by key. Note the quotes around '1': the assigned\n-- value must be of the jsonb type as well\nUPDATE table_name SET jsonb_field['key'] = '1';\n\n-- This will raise an error if any record's jsonb_field['a']['b'] is something\n-- other than an object. For example, the value {\"a\": 1} has a numeric value\n-- of the key 'a'.\nUPDATE table_name SET jsonb_field['a']['b']['c'] = '1';\n\n-- Filter records using a WHERE clause with subscripting. Since the result of\n-- subscripting is jsonb, the value we compare it against must also be jsonb.\n-- The double quotes make \"value\" also a valid jsonb string.\nSELECT * FROM table_name WHERE jsonb_field['key'] = '\"value\"';\n</pre>\n<p lang=\"zh\">通过下标进行的 <code class=\"type\">jsonb</code> 赋值在若干边界情况下与 <code class=\"literal\">jsonb_set</code> 的行为不同。当源 <code class=\"type\">jsonb</code> 值为 <code class=\"literal\">NULL</code> 时，下标赋值会把它当作由下标键所暗示的类型（对象或数组）的空 JSON 值来处理：</p>\n<pre class=\"programlisting\">-- Where jsonb_field was NULL, it is now {\"a\": 1}\nUPDATE table_name SET jsonb_field['a'] = '1';\n\n-- Where jsonb_field was NULL, it is now [1]\nUPDATE table_name SET jsonb_field[0] = '1';\n</pre>\n<p lang=\"zh\">如果对一个元素数量不足的数组指定了某个下标，就会不断追加 <code class=\"literal\">NULL</code> 元素，直到该下标可达并且可以设置该值为止。</p>\n<pre class=\"programlisting\">-- Where jsonb_field was [], it is now [null, null, 2];\n-- where jsonb_field was [0], it is now [0, null, 2]\nUPDATE table_name SET jsonb_field[2] = '2';\n</pre>\n<p lang=\"zh\">只要沿路径遍历时最后一个已存在的元素是对象或数组（与对应下标所暗示的类型一致；路径中最后一个下标指向的元素本身不会被遍历，因此它可以是任何值），那么 <code class=\"type\">jsonb</code> 值就接受对不存在下标路径的赋值。系统会根据下标路径创建嵌套的数组和对象结构；在前一种情况下还会按需要以 <code class=\"literal\">null</code> 填充，直到能够放入被赋值的值为止。</p>\n<pre class=\"programlisting\">-- Where jsonb_field was {}, it is now {\"a\": [{\"b\": 1}]}\nUPDATE table_name SET jsonb_field['a'][0]['b'] = '1';\n\n-- Where jsonb_field was [], it is now [null, {\"a\": 1}]\nUPDATE table_name SET jsonb_field[1]['a'] = '1';\n</pre>\n</div>\n<div class=\"sect2\" id=\"DATATYPE-JSON-TRANSFORMS\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/datatype-json.html#DATATYPE-JSON-TRANSFORMS\">8.14.6. 转换</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\">还提供了一些附加扩展，为不同过程语言实现了 <code class=\"type\">jsonb</code> 类型的转换。</p>\n<p lang=\"zh\">PL/Perl 的扩展名为 <code class=\"literal\">jsonb_plperl</code> 和 <code class=\"literal\">jsonb_plperlu</code>。如果使用它们，<code class=\"type\">jsonb</code> 值会按适当方式映射为 Perl 数组、hash 和标量。</p>\n<p lang=\"zh\">PL/Python 的扩展名为 <code class=\"literal\">jsonb_plpython3u</code>。如果使用它，<code class=\"type\">jsonb</code> 值会按适当方式映射为 Python 字典、列表和标量。</p>\n<p lang=\"zh\">在这些扩展中，<code class=\"literal\">jsonb_plperl</code> 被视为<span class=\"quote\">“<span class=\"quote\">受信任的</span>”</span>，也就是说，它可以由在当前数据库上拥有 <code class=\"literal\">CREATE</code> 权限的非超级用户安装。其余扩展则需要超级用户权限才能安装。</p>\n</div>\n<div class=\"sect2\" id=\"DATATYPE-JSONPATH\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h3 class=\"title\" lang=\"zh\"><span class=\"sect2\"><a href=\"/docs/18/datatype-json.html#DATATYPE-JSONPATH\">8.14.7. jsonpath 类型</a></span></h3>\n</div>\n</div>\n</div>\n<p lang=\"zh\"><code class=\"type\">jsonpath</code> 类型在 <span class=\"productname\">PostgreSQL</span> 中实现了对 SQL/JSON 路径语言的支持，以便高效查询 JSON 数据。它提供了解析后的 SQL/JSON 路径表达式的二进制表示，该表达式指定路径引擎应从 JSON 数据中检索哪些项，以便由 SQL/JSON 查询函数做进一步处理。</p>\n<p lang=\"zh\">SQL/JSON 路径谓词和操作符的语义通常遵循 SQL。同时，为了以更自然的方式处理 JSON 数据，SQL/JSON 路径语法采用了一些 JavaScript 约定：</p>\n<div class=\"itemizedlist\">\n<ul class=\"itemizedlist\">\n<li class=\"listitem\" lang=\"zh\">\n<p>点号（<code class=\"literal\">.</code>）用于成员访问。</p>\n</li>\n<li class=\"listitem\" lang=\"zh\">\n<p>方括号（<code class=\"literal\">[]</code>）用于数组访问。</p>\n</li>\n<li class=\"listitem\" lang=\"zh\">SQL/JSON 数组从 0 开始编号，与从 1 开始的普通 SQL 数组不同。</li>\n</ul>\n</div>\n<p lang=\"zh\">SQL/JSON 路径表达式中的数字字面量遵循 JavaScript 规则，这在一些细节上与 SQL 和 JSON 都不同。例如，SQL/JSON 路径允许 <code class=\"literal\">.1</code> 和 <code class=\"literal\">1.</code>，而它们在 JSON 中是无效的。还支持非十进制整数字面量和下划线分隔符，例如 <code class=\"literal\">1_000_000</code>、<code class=\"literal\">0x1EEE_FFFF</code>、<code class=\"literal\">0o273</code>、<code class=\"literal\">0b100101</code>。在 SQL/JSON 路径中（以及 JavaScript 中，但 SQL 本身并非如此），基数前缀后面不能直接出现下划线分隔符。</p>\n<p lang=\"zh\">SQL/JSON 路径表达式通常在 SQL 查询中写成 SQL 字符串字面量，因此它必须用单引号括起来，而值中若要出现单引号，则必须写成两个单引号（见<a class=\"xref\" href=\"/docs/18/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS\" title=\"4.1.2.1. 字符串常量\">第 4.1.2.1 节</a>）。某些形式的路径表达式还要求其中再包含字符串字面量。这些嵌入式字符串字面量遵循 JavaScript/ECMAScript 约定：它们必须用双引号括起，并且可以在其中使用反斜杠转义来表示其他难以输入的字符。特别地，在嵌入式字符串字面量中写双引号要使用 <code class=\"literal\">\\\"</code>，写反斜杠本身则必须写成 <code class=\"literal\">\\\\</code>。其他特殊反斜杠序列包括 JavaScript 字符串中识别的下列几种：<code class=\"literal\">\\b</code>、<code class=\"literal\">\\f</code>、<code class=\"literal\">\\n</code>、<code class=\"literal\">\\r</code>、<code class=\"literal\">\\t</code>、<code class=\"literal\">\\v</code>，用于各种 ASCII 控制字符；<code class=\"literal\">\\x<em class=\"replaceable\"><code>NN</code></em></code> 表示仅用两个十六进制数字写出的字符码；<code class=\"literal\">\\u<em class=\"replaceable\"><code>NNNN</code></em></code> 表示由 4 位十六进制码点标识的 Unicode 字符；<code class=\"literal\">\\u{<em class=\"replaceable\"><code>N...</code></em>}</code> 则表示用 1 到 6 位十六进制数字写出的 Unicode 字符码点。</p>\n<p lang=\"zh\">路径表达式由一系列路径元素构成，这些元素可以是下列任意一种：</p>\n<div class=\"itemizedlist\">\n<ul class=\"itemizedlist\">\n<li class=\"listitem\" lang=\"zh\">\n<p>JSON 基本类型的路径字面量：Unicode 文本、数值、true、false 或 null。</p>\n</li>\n<li class=\"listitem\" lang=\"zh\">\n<p><a class=\"xref\" href=\"/docs/18/datatype-json.html#TYPE-JSONPATH-VARIABLES\" title=\"表 8.24. jsonpath 变量\">表 8.24</a>中列出的路径变量。</p>\n</li>\n<li class=\"listitem\" lang=\"zh\">\n<p><a class=\"xref\" href=\"/docs/18/datatype-json.html#TYPE-JSONPATH-ACCESSORS\" title=\"表 8.25. jsonpath 访问器\">表 8.25</a>中列出的访问器操作符。</p>\n</li>\n<li class=\"listitem\" lang=\"zh\">\n<p><code class=\"type\">jsonpath</code> 操作符和方法，列于<a class=\"xref\" href=\"/docs/18/functions-json.html#FUNCTIONS-SQLJSON-PATH-OPERATORS\" title=\"9.16.2.3. SQL/JSON 路径操作符和方法\">第 9.16.2.3 节</a>。</p>\n</li>\n<li class=\"listitem\" lang=\"zh\">\n<p>括号，可用于提供过滤表达式或定义路径求值顺序。</p>\n</li>\n</ul>\n</div>\n<p lang=\"zh\">关于在 SQL/JSON 查询函数中使用 <code class=\"type\">jsonpath</code> 表达式的细节，见<a class=\"xref\" href=\"/docs/18/functions-json.html#FUNCTIONS-SQLJSON-PATH\" title=\"9.16.2. SQL/JSON 路径语言\">第 9.16.2 节</a>。</p>\n<div class=\"table\" id=\"TYPE-JSONPATH-VARIABLES\">\n<p class=\"title\" lang=\"zh\"><strong>表 8.24. <code class=\"type\">jsonpath</code> 变量</strong></p>\n<div class=\"table-contents\">\n<table class=\"table\">\n<thead>\n<tr>\n<th lang=\"zh\">变量</th>\n<th lang=\"zh\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code class=\"literal\">$</code></td>\n<td lang=\"zh\">表示正在被查询的 JSON 值的变量（<em class=\"firstterm\">上下文项</em>）。</td>\n</tr>\n<tr>\n<td><code class=\"literal\">$varname</code></td>\n<td lang=\"zh\">命名变量。它的值可以由若干 JSON 处理函数的 <em class=\"parameter\"><code>vars</code></em> 参数设置；详见<a class=\"xref\" href=\"/docs/18/functions-json.html#FUNCTIONS-JSON-PROCESSING-TABLE\" title=\"表 9.51. JSON 处理函数\">表 9.51</a>。</td>\n</tr>\n<tr>\n<td><code class=\"literal\">@</code></td>\n<td lang=\"zh\">表示过滤表达式中路径求值结果的变量。</td>\n</tr>\n</tbody>\n</table>\n</div>\n</div><br class=\"table-break\"/>\n<div class=\"table\" id=\"TYPE-JSONPATH-ACCESSORS\">\n<p class=\"title\" lang=\"zh\"><strong>表 8.25. <code class=\"type\">jsonpath</code> 访问器</strong></p>\n<div class=\"table-contents\">\n<table class=\"table\">\n<thead>\n<tr>\n<th lang=\"zh\">访问器操作符</th>\n<th lang=\"zh\">说明</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>\n<p><code class=\"literal\">.<em class=\"replaceable\"><code>key</code></em></code></p>\n<p><code class=\"literal\">.\"$<em class=\"replaceable\"><code>varname</code></em>\"</code></p>\n</td>\n<td lang=\"zh\">\n<p>成员访问器，用于返回指定键对应的对象成员。如果键名与某个以 <code class=\"literal\">$</code> 开头的命名变量相同，或者不符合 JavaScript 对标识符的规则，就必须用双引号将其括起，使其成为字符串字面量。</p>\n</td>\n</tr>\n<tr>\n<td>\n<p><code class=\"literal\">.*</code></p>\n</td>\n<td lang=\"zh\">\n<p>通配符成员访问器，返回当前对象顶层所有成员的值。</p>\n</td>\n</tr>\n<tr>\n<td>\n<p><code class=\"literal\">.**</code></p>\n</td>\n<td lang=\"zh\">\n<p>递归通配符成员访问器，处理当前对象 JSON 层次结构的所有层级，并返回所有成员值，而不论其嵌套层级如何。这是 <span class=\"productname\">PostgreSQL</span> 对 SQL/JSON 标准的扩展。</p>\n</td>\n</tr>\n<tr>\n<td>\n<p><code class=\"literal\">.**{<em class=\"replaceable\"><code>level</code></em>}</code></p>\n<p><code class=\"literal\">.**{<em class=\"replaceable\"><code>start_level</code></em> to <em class=\"replaceable\"><code>end_level</code></em>}</code></p>\n</td>\n<td lang=\"zh\">\n<p>类似 <code class=\"literal\">.**</code>，但只选择 JSON 层次结构中指定的层级。嵌套层级以整数指定。层级零对应当前对象。若要访问最深的嵌套层级，可以使用 <code class=\"literal\">last</code> 关键字。这是 <span class=\"productname\">PostgreSQL</span> 对 SQL/JSON 标准的扩展。</p>\n</td>\n</tr>\n<tr>\n<td>\n<p><code class=\"literal\">[<em class=\"replaceable\"><code>subscript</code></em>, ...]</code></p>\n</td>\n<td lang=\"zh\">\n<p>数组元素访问器。<code class=\"literal\"><em class=\"replaceable\"><code>subscript</code></em></code> 可以用两种形式给出：<code class=\"literal\"><em class=\"replaceable\"><code>index</code></em></code> 或 <code class=\"literal\"><em class=\"replaceable\"><code>start_index</code></em> to <em class=\"replaceable\"><code>end_index</code></em></code>。第一种形式按下标返回单个数组元素。第二种形式按下标范围返回数组切片，其中包括与给定 <em class=\"replaceable\"><code>start_index</code></em> 和 <em class=\"replaceable\"><code>end_index</code></em> 对应的元素。</p>\n<p>指定的 <em class=\"replaceable\"><code>index</code></em> 可以是整数，也可以是返回单个数值的表达式，该数值会自动转换为整数。下标零对应第一个数组元素。你也可以使用 <code class=\"literal\">last</code> 关键字来表示最后一个数组元素，这对于处理长度未知的数组很有用。</p>\n</td>\n</tr>\n<tr>\n<td>\n<p><code class=\"literal\">[*]</code></p>\n</td>\n<td lang=\"zh\">\n<p>通配符数组元素访问器，返回所有数组元素。</p>\n</td>\n</tr>\n</tbody>\n</table>\n</div>\n</div><br class=\"table-break\"/>\n</div>\n<div class=\"footnotes\">\n<br/>\n<div class=\"footnote\" id=\"ftn.id-1.5.7.22.18.9.3\">\n<p lang=\"zh\">\n<br/>\n<hr style=\"width:100; text-align:left;margin-left: 0\"/>\n<div class=\"footnote\" id=\"ftn.id-1.5.7.22.18.9.3\">\n<p><a class=\"para\" href=\"/docs/18/datatype-json.html#id-1.5.7.22.18.9.3\"><sup class=\"para\">[7]</sup></a> 在这里，术语<span class=\"quote\">“<span class=\"quote\">值</span>”</span>也包括数组元素，尽管在 JSON 术语中，有时会把数组元素与对象中的值区分开来。</p>\n</div>\n</p>\n</div>\n</div>\n</div>", "manual_path": "datatype-json.html", "localization": {"status": "complete", "sources": [{"url": "/docs/18/datatype-json.html", "method": "same-major semantic node", "sha256": "b9e8f98a0b5f2a4ec7b5197d02ab40c0ac0635a678c32728aaadd43cb4cd3766", "language": "zh", "matched_nodes": ["#DATATYPE-JSON/div[0]", "#DATATYPE-JSON/div[11]/h3[0]", "#DATATYPE-JSON/div[11]/p[1]", "#DATATYPE-JSON/div[14]/div[1]/table[0]/tbody[2]/tr[0]/td[2]", "#DATATYPE-JSON/div[14]/div[1]/table[0]/tbody[2]/tr[1]/td[2]", "#DATATYPE-JSON/div[14]/div[1]/table[0]/tbody[2]/tr[2]/td[2]", "#DATATYPE-JSON/div[14]/div[1]/table[0]/tbody[2]/tr[3]/td[1]", "#DATATYPE-JSON/div[14]/div[1]/table[0]/tbody[2]/tr[3]/td[2]", "#DATATYPE-JSON/div[14]/div[1]/table[0]/thead[1]/tr[0]/th[0]", "#DATATYPE-JSON/div[14]/div[1]/table[0]/thead[1]/tr[0]/th[1]", "#DATATYPE-JSON/div[14]/div[1]/table[0]/thead[1]/tr[0]/th[2]", "#DATATYPE-JSON/div[14]/p[0]", "#DATATYPE-JSON/div[16]/p[2]", "#DATATYPE-JSON/div[16]/p[4]", "#DATATYPE-JSON/div[16]/p[6]", "#DATATYPE-JSON/div[16]/p[8]", "#DATATYPE-JSON/div[16]/p[9]", "#DATATYPE-JSON/div[17]/p[1]", "#DATATYPE-JSON/div[17]/p[2]", "#DATATYPE-JSON/div[18]/div[11]/h3[0]", "#DATATYPE-JSON/div[18]/div[11]/p[1]", "#DATATYPE-JSON/div[18]/div[11]/p[3]", "#DATATYPE-JSON/div[18]/div[11]/p[5]", "#DATATYPE-JSON/div[18]/div[11]/p[6]", "#DATATYPE-JSON/div[18]/p[10]", "#DATATYPE-JSON/div[18]/p[12]", "#DATATYPE-JSON/div[18]/p[3]", "#DATATYPE-JSON/div[18]/p[5]", "#DATATYPE-JSON/div[18]/p[6]", "#DATATYPE-JSON/div[18]/p[8]", "#DATATYPE-JSON/div[19]/p[11]", "#DATATYPE-JSON/div[19]/p[13]", "#DATATYPE-JSON/div[19]/p[15]", "#DATATYPE-JSON/div[19]/p[16]", "#DATATYPE-JSON/div[19]/p[18]", "#DATATYPE-JSON/div[19]/p[19]", "#DATATYPE-JSON/div[19]/p[23]", "#DATATYPE-JSON/div[19]/p[24]", "#DATATYPE-JSON/div[19]/p[25]", "#DATATYPE-JSON/div[19]/p[26]", "#DATATYPE-JSON/div[19]/p[28]", "#DATATYPE-JSON/div[19]/p[2]", "#DATATYPE-JSON/div[19]/p[30]", "#DATATYPE-JSON/div[19]/p[32]", "#DATATYPE-JSON/div[19]/p[34]", "#DATATYPE-JSON/div[19]/p[3]", "#DATATYPE-JSON/div[19]/p[5]", "#DATATYPE-JSON/div[19]/p[7]", "#DATATYPE-JSON/div[1]/dl[0]/dt[0]", "#DATATYPE-JSON/div[1]/dl[0]/dt[1]", "#DATATYPE-JSON/div[1]/dl[0]/dt[2]", "#DATATYPE-JSON/div[1]/dl[0]/dt[3]", "#DATATYPE-JSON/div[1]/dl[0]/dt[4]", "#DATATYPE-JSON/div[1]/dl[0]/dt[5]", "#DATATYPE-JSON/div[1]/dl[0]/dt[6]", "#DATATYPE-JSON/div[20]/p[3]", "#DATATYPE-JSON/div[20]/p[5]", "#DATATYPE-JSON/div[20]/p[7]", "#DATATYPE-JSON/div[20]/p[9]", "#DATATYPE-JSON/div[21]/p[1]", "#DATATYPE-JSON/div[21]/p[2]", "#DATATYPE-JSON/div[21]/p[3]", "#DATATYPE-JSON/div[21]/p[4]", "#DATATYPE-JSON/div[22]/div[10]/div[1]/table[0]/tbody[2]/tr[0]/td[1]", "#DATATYPE-JSON/div[22]/div[10]/div[1]/table[0]/tbody[2]/tr[1]/td[1]", "#DATATYPE-JSON/div[22]/div[10]/div[1]/table[0]/tbody[2]/tr[2]/td[1]", "#DATATYPE-JSON/div[22]/div[10]/p[0]", "#DATATYPE-JSON/div[22]/div[12]/div[1]/table[0]/tbody[2]/tr[0]/td[1]", "#DATATYPE-JSON/div[22]/div[12]/div[1]/table[0]/tbody[2]/tr[1]/td[1]", "#DATATYPE-JSON/div[22]/div[12]/div[1]/table[0]/tbody[2]/tr[2]/td[1]", "#DATATYPE-JSON/div[22]/div[12]/div[1]/table[0]/tbody[2]/tr[3]/td[1]", "#DATATYPE-JSON/div[22]/div[12]/div[1]/table[0]/tbody[2]/tr[4]/td[1]", "#DATATYPE-JSON/div[22]/div[12]/div[1]/table[0]/tbody[2]/tr[5]/td[1]", "#DATATYPE-JSON/div[22]/div[12]/div[1]/table[0]/thead[1]/tr[0]/th[0]", "#DATATYPE-JSON/div[22]/div[12]/p[0]", "#DATATYPE-JSON/div[22]/div[4]/ul[0]/li[0]", "#DATATYPE-JSON/div[22]/div[4]/ul[0]/li[1]", "#DATATYPE-JSON/div[22]/div[8]/ul[0]/li[0]", "#DATATYPE-JSON/div[22]/div[8]/ul[0]/li[1]", "#DATATYPE-JSON/div[22]/div[8]/ul[0]/li[2]", "#DATATYPE-JSON/div[22]/div[8]/ul[0]/li[3]", "#DATATYPE-JSON/div[22]/div[8]/ul[0]/li[4]", "#DATATYPE-JSON/div[22]/p[2]", "#DATATYPE-JSON/div[22]/p[3]", "#DATATYPE-JSON/div[22]/p[5]", "#DATATYPE-JSON/div[22]/p[6]", "#DATATYPE-JSON/div[22]/p[7]", "#DATATYPE-JSON/div[22]/p[9]", "#DATATYPE-JSON/div[23]", "#DATATYPE-JSON/p[10]", "#DATATYPE-JSON/p[13]", "#DATATYPE-JSON/p[4]", "#DATATYPE-JSON/p[5]", "#DATATYPE-JSON/p[6]", "#DATATYPE-JSON/p[7]", "#DATATYPE-JSON/p[8]", "#DATATYPE-JSON/p[9]"]}, {"url": "/docs/18/functions-matching.html", "method": "same-major semantic node", "sha256": "704120d783880b39b956c073d1a82ba1f40b35068b4d3b9a195f543b86c3a22a", "language": "zh", "matched_nodes": ["#FUNCTIONS-MATCHING/div[9]/div[51]/p[2]/em[2]"]}, {"url": "/docs/18/protocol-overview.html", "method": "same-major semantic node", "sha256": "3f1aa8bd4dbef58e9a82e8cf4c82829a4df7416cfa83dd61c18e9e25060f22da", "language": "zh", "matched_nodes": ["#PROTOCOL-OVERVIEW/div[9]/p[1]/span[2]/span[0]"]}], "language": "zh", "original_text": {"/versions/18/description/0": "JSON path", "/versions/18/facts/0/label": "Catalog name", "/versions/18/facts/1/label": "Type OID", "/versions/18/facts/2/label": "Type kind", "/versions/18/facts/2/value": "Base type", "/versions/18/facts/3/label": "Declared length", "/versions/18/facts/3/value": "Variable length (varlena)", "/versions/18/facts/4/label": "Storage strategy", "/versions/18/facts/4/value": "extended", "/versions/18/facts/5/label": "Input function", "/versions/18/facts/6/label": "Output function", "/versions/18/related/0/label": "pg_type catalog", "/versions/18/related/1/label": "pg_cast catalog", "/versions/18/related/2/label": "pg_operator catalog", "/versions/18/related/3/label": "pg_opclass catalog", "/versions/18/related/4/label": "Arrays"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "e1e38e9c615e70c6e5265e3d983f190e27b41a488896f4681827ceed535b3d0a"}, "comparison_data": {"casts": [], "facts": [{"label": "Catalog name", "value": "pg_catalog.jsonpath"}, {"label": "Declared length", "value": "Variable length (varlena)"}, {"label": "Input function", "value": "jsonpath_in"}, {"label": "Output function", "value": "jsonpath_out"}, {"label": "Storage strategy", "value": "extended"}, {"label": "Type OID", "value": "4072"}, {"label": "Type kind", "value": "Base type"}], "ranges": [], "aliases": [], "catalog": {"typacl": "_null_", "typlen": "-1", "typelem": "0", "typname": "jsonpath", "typsend": "jsonpath_send", "typtype": "b", "typalign": "i", "typarray": "_jsonpath", "typbyval": "f", "typdelim": ",", "typinput": "jsonpath_in", "typmodin": "-", "typndims": "0", "typrelid": "0", "typmodout": "-", "typoutput": "jsonpath_out", "typtypmod": "-1", "typanalyze": "-", "typdefault": "_null_", "typnotnull": "f", "typreceive": "jsonpath_recv", "typstorage": "x", "typbasetype": "0", "typcategory": "U", "typcollation": "0", "typisdefined": "t", "typsubscript": "-", "typdefaultbin": "_null_", "typispreferred": "f", "array_type_name": "_jsonpath"}, "operators": [{"oprcom": "0", "oprcode": "jsonb_path_exists_opr", "oprjoin": "matchingjoinsel", "oprkind": "b", "oprleft": "jsonb", "oprname": "@?", "oprrest": "matchingsel", "oprright": "jsonpath", "oprnegate": "0", "oprresult": "bool", "oprcanhash": "f", "oprcanmerge": "f"}, {"oprcom": "0", "oprcode": "jsonb_path_match_opr", "oprjoin": "matchingjoinsel", "oprkind": "b", "oprleft": "jsonb", "oprname": "@@", "oprrest": "matchingsel", "oprright": "jsonpath", "oprnegate": "0", "oprresult": "bool", "oprcanhash": "f", "oprcanmerge": "f"}], "operator_classes": []}, "comparison_hash": "4f20758056bad40316d444909f896c5a227fea648d1d6edd1f55db00e8d871ee", "manual_language": "zh", "operator_classes": [], "manual_documentation": "dedicated family chapter"}, "from": "17", "comparison": {"available": true, "changes": [], "prose_changed": true}}