jsonb 연산자와 함수#

속성은 jsonb입니다. 정점은 복합 타입 (id graphid, properties jsonb)이고, 간선에는 start와 end가 더해집니다. 그러므로 Cypher에서 읽는 모든 속성과 SQL에서 손대는 모든 속성 컬럼이 PostgreSQL jsonb 타입의 값입니다. 이 페이지의 다른 무엇보다 먼저 받아들여야 할 결과가 두 가지입니다. 문자열 속성은 따옴표와 함께 돌아오고, jsonb 연산자 전체가 그것에 적용됩니다.

예제는 예제 데이터셋에서 실행됩니다.

속성 접근 연산자#

이 네 개는 왼쪽에 jsonb 값을 받습니다. 화살표가 겹친 둘은 text를 반환하고, 화살표가 하나인 둘은 jsonb를 반환합니다.

연산자

오른쪽 피연산자

반환 타입

결과

->

text 키 또는 integer 인덱스

jsonb

그 키나 인덱스에 있는 값

->>

text 키 또는 integer 인덱스

text

같은 값이며, 문자열은 따옴표가 벗겨진 상태

#>

text[] 경로

jsonb

그 경로에 있는 값

#>>

text[] 경로

text

같은 값이며, 문자열은 따옴표가 벗겨진 상태

SELECT properties -> 'name' AS quoted, properties ->> 'name' AS plain
FROM moviekb.person ORDER BY id LIMIT 1;
     quoted     |    plain
----------------+--------------
 "Keanu Reeves" | Keanu Reeves
SELECT '{"a":{"b":[1,2]}}'::jsonb #> '{a,b}' AS at_path,
       '{"a":{"b":[1,2]}}'::jsonb #>> '{a,b,0}' AS at_path_text;
 at_path | at_path_text
---------+--------------
 [1, 2]  | 1

따옴표 없는 스칼라로 꺼내기#

Cypher의 RETURN은 스칼라 출력 컬럼을 jsonb로 감쌉니다. 그래서 RETURN m.title은 따옴표까지 포함해 "Inception"을 출력하고, RETURN m.title::text도 그렇습니다. 그 따옴표는 psql이 만든 것이 아니라 JSON의 일부입니다.

빠져나가는 길은 #>> '{}'입니다. 빈 경로가 문서 전체를 고르고, #>>이 그것을 text로 반환합니다. Cypher를 SQL로 감싸고 거기서 적용하십시오:

SELECT t AS boxed, t #>> '{}' AS unboxed
FROM (MATCH (m:movie {title:'Inception'}) RETURN m.title AS t) q;
    boxed    |  unboxed
-------------+-----------
 "Inception" | Inception

Cypher 결과를 평범한 text와 조인하거나 비교해야 할 때는 언제든 이 관용구를 꺼내 쓰십시오. 관계형 테이블과의 조인이 그런 경우입니다.

포함·존재 연산자#

연산자

오른쪽 피연산자

참이 되는 조건

@>

jsonb

왼쪽 문서가 오른쪽 문서를 포함할 때

<@

jsonb

왼쪽 문서가 오른쪽 문서에 포함될 때

?

text

그 키나 문자열 요소가 있을 때

`?

`

text[]

?&

text[]

그 키가 모두 있을 때

SELECT properties @> '{"name":"Keanu Reeves"}' AS contains,
       properties ? 'born' AS has_born,
       properties ?& ARRAY['name','born'] AS has_both
FROM moviekb.person ORDER BY id LIMIT 1;
 contains | has_born | has_both
----------+----------+----------
 t        | t        | t

속성 인덱스는 이 중 어느 것도 처리할 수 없습니다. 각각 키 하나와의 비교가 아니라 properties 전체에 대한 포함 검사이기 때문입니다. properties에 걸린 GIN 인덱스는 처리할 수 있습니다.

변경 연산자#

연산자

오른쪽 피연산자

결과

||

jsonb

두 문서를 병합한 것이며, 공유된 키에서는 오른쪽이 이깁니다

-

text 키 또는 integer 인덱스

그 키나 요소가 빠진 문서

#-

text[] 경로

그 경로의 값이 빠진 문서

SELECT '{"a":1}'::jsonb || '{"b":2}'::jsonb AS merged,
       '{"a":1,"b":2}'::jsonb - 'a' AS without_a,
       '{"a":{"b":1}}'::jsonb #- '{a,b}' AS without_path;
      merged      | without_a | without_path
------------------+-----------+--------------
 {"a": 1, "b": 2} | {"b": 2}  | {"a": {}}

Cypher에서는 이것들을 대신 절로 표기합니다. SET n += {city:'Seoul'}이 병합하고 REMOVE n.city가 키를 지웁니다.

jsonb에 대한 산술 연산자#

PostgreSQL이 이미 jsonb에 대해 -와 ||에 뜻을 주었으므로, AgensGraph는 그것을 산술에 다시 쓸 수 없었습니다. 그래서 이름을 백틱으로 감싼 연산자 여덟 개를 더했습니다. 속성에 +, -, *, /, %, ^를 쓰면 Cypher 파서가 그것들을 내놓습니다.

연산자

구현 함수

OID

뜻

`+`

jsonb_add

7176

덧셈. 문자열 둘이나 리스트 둘이면 이어 붙이기

`-`

jsonb_sub

7178

뺄셈

`*`

jsonb_mul

7180

곱셈

`/`

jsonb_div

7182

나눗셈. 두 피연산자가 모두 정수면 정수 나눗셈

`%`

jsonb_mod

7184

나머지

`^`

jsonb_pow

7186

거듭제곱

`+` (접두)

jsonb_uplus

7190

단항 플러스

`-` (접두)

jsonb_uminus

7191

단항 마이너스

이 포크의 렉서에서 백틱은 연산자 문자이므로(scan.l:369), 이 이름들은 SQL에서도 입력할 수 있습니다. 두 피연산자 모두 jsonb여야 합니다:

SELECT '"a"'::jsonb `+` '"b"'::jsonb AS strings, '[1]'::jsonb `+` '[2]'::jsonb AS lists;
 strings | lists
---------+--------
 "ab"    | [1, 2]

참고

Cypher의 산술은 평범한 연산자로 쓰고 — n.a + n.b — 파서가 이것들을 고르게 하십시오. 백틱 이름이 여기 있는 것은 EXPLAIN 계획이나 오류 메시지, pg_operator 목록에서 그것을 알아볼 수 있게 하려는 것입니다. 구현 함수를 직접 호출할 수도 있습니다. jsonb_add('1'::jsonb, '2'::jsonb)은 3을 반환합니다.

ag_property_text#

2.18에 추가

ag_property_text ( properties jsonb, key text, expected_kind "char" ) -> text

속성의 값을 text로 반환하지만, 저장된 값이 요구한 JSON 종류일 때만 그렇습니다.

이름

타입

설명

properties

jsonb

읽을 속성 맵입니다.

key

text

속성의 이름입니다.

expected_kind

"char"

숫자는 'n', 문자열은 's', 불리언은 'b'입니다.

고려할 점

  • 이 함수가 타입 컬럼 속성 승격의 뒤를 받칩니다. ->>은 값의 텍스트를 반환하고 텍스트에는 종류가 없으므로, 그것을 통해서는 문자열 "5"와 숫자 5를 구별할 수 없습니다. 정수 컬럼이라면 문자열을 담은 속성에 대해 5라고 답해 버립니다. 이 함수는 종류를 먼저 묻습니다.

  • 종류가 맞지 않으면 null을 반환하는 것이 아니라 오류를 냅니다. property "n" holds a number가 나오고 상세로 A column promoting this property holds strings. 가 따라옵니다.

  • 없는 속성, 또는 있으면서 JSON null인 속성은 null을 반환합니다.

  • 손으로 쓰도록 만든 함수가 아닙니다. 속성은 Cypher에서 n.key로, SQL에서 properties ->> 'key'로 읽으십시오.

SELECT ag_property_text('{"name":"x","n":5}'::jsonb, 'n', 'n') AS number,
       ag_property_text('{"name":"x"}'::jsonb, 'missing', 's') AS absent;
 number | absent
--------+--------
 5      |

cypher_to_jsonb#

cypher_to_jsonb ( value anyelement ) -> jsonb

Cypher의 규칙으로 값을 jsonb로 감쌉니다. 그 규칙은 문자열 타입에 대해 to_jsonb의 규칙과 다릅니다.

고려할 점

  • Cypher의 RETURN이 스칼라 출력 컬럼을 감쌀 때 넣는 함수가 이것입니다. 실행 계획에서 그 감싸기가 일어나는 지점에 나타납니다.

  • 엄격 함수이므로 null은 null로 남습니다.

  • 파서는 그래프 요소를 이 함수로 감싸기를 거부합니다. 그 거부 때문에 coalesce(m, 0)과 정점을 담은 jsonb 리스트가 실패합니다. 그 거부는 함수가 아니라 파서의 coerce_to_jsonb()에 있습니다. vertex에 대해 이름으로 직접 호출하면 이 함수는 id와 tid까지 포함한 복합 타입 전체를 반환하며, 그것은 v::jsonb가 주는 properties가 아닙니다. 그것을 원하면 vertex_to_jsonb나 형 변환을 쓰십시오.

SELECT cypher_to_jsonb('abc'::text) AS from_text, cypher_to_jsonb(42) AS from_integer;
 from_text | from_integer
-----------+--------------
 "abc"     | 42

edge_to_jsonb#

edge_to_jsonb ( e edge ) -> jsonb

간선의 properties를 반환합니다. 형 변환 e::jsonb가 쓰는 함수가 이것이고, properties(e)와 같은 값을 반환합니다.

고려할 점

  • 양 끝점은 포함되지 않고 속성만 포함됩니다. 끝점은 start_id와 end_id로 읽으십시오.

MATCH ()-[e:related_to]->() WITH e LIMIT 1 RETURN edge_to_jsonb(e) AS bag;
      bag
---------------
 {"weight": 1}

graphid_in_jsonb_array#

graphid_in_jsonb_array ( id graphid, elements jsonb ) -> boolean

graphid가 jsonb 배열에 담긴 그래프 요소 중 하나이면 참을 반환합니다.

고려할 점

  • 파서가 id(n) IN [...]에 대해 이 함수를 내놓아서, 요소 목록을 하나하나 벗겨 내지 않고도 검사할 수 있게 합니다. graphid는 jsonb 문자열로 감싸이고, 이 함수는 그 형태와 비교합니다.

  • 손으로 쓰면 평범한 소속 검사입니다.

SELECT graphid_in_jsonb_array('4.1'::graphid, '["4.1","4.2"]'::jsonb) AS present;
 present
---------
 t

jsonb_array_length#

jsonb_array_length ( list jsonb ) -> integer

jsonb 배열의 요소 개수를 integer로 반환합니다.

고려할 점

  • PostgreSQL 자신의 함수입니다. cardinality와 length가 Cypher 쪽 표기이고 jsonb를 반환합니다. 이 함수는 네이티브 integer를 반환하고, 배열이 아닌 값에 대해서는 오류를 냅니다.

SELECT jsonb_array_length('[1,2,3]');
 jsonb_array_length
--------------------
                  3

to_jsonb#

to_jsonb ( value anyelement ) -> jsonb

어떤 SQL 값이든 jsonb로 변환하며, 복합 타입은 객체로, 배열은 배열로 대응시킵니다.

고려할 점

  • 관계형 행을 그래프로 들여오는 방법이 이것입니다. LOAD FROM t AS r CREATE (:label = to_jsonb(row_to_json(r)))가 각 행을 properties로 바꿉니다.

  • 그래프 요소에 대해서는 properties가 아니라 복합 타입 전체를 변환합니다. properties를 주는 것은 v::jsonb와 vertex_to_jsonb입니다.

SELECT to_jsonb(42) AS number, to_jsonb('x'::text) AS string;
 number | string
--------+--------
 42     | "x"

vertex_to_jsonb#

vertex_to_jsonb ( v vertex ) -> jsonb

정점의 properties를 반환합니다. 형 변환 v::jsonb가 쓰는 함수가 이것이고, properties(v)와 같은 값을 반환합니다.

MATCH (n:person {name:'Keanu Reeves'}) RETURN vertex_to_jsonb(n) AS bag;
                  bag
----------------------------------------
 {"born": 1964, "name": "Keanu Reeves"}

순서와 비교#

jsonb에는 자기만의 전순서가 있고, 그것은 값들이 자기 타입에서 가질 순서가 아닙니다. 종류가 먼저 옵니다. null, 그다음 문자열, 그다음 숫자, 그다음 불리언, 그다음 배열, 그다음 객체입니다. 같은 종류의 값만 값으로 비교됩니다:

SELECT v FROM (VALUES ('1'::jsonb),('"a"'),('true'),('null'),('[1]'),('{"k":1}')) t(v) ORDER BY v;
    v
----------
 null
 "a"
 1
 true
 [1]
 {"k": 1}

Cypher 결과를 정렬하거나 집계하는 곳이면 어디서나 이것이 문제가 됩니다. jsonb 컬럼에 대한 min()과 max()가 그 순서를 따르므로, 어떤 행에서는 숫자를 담고 어떤 행에서는 문자열을 담는 속성은 읽는 사람이 기대하는 대로 정렬되지 않습니다. 순서가 그 타입 자신의 것이어야 한다면 타입 컬럼을 통해 읽거나 형 변환을 하십시오.

정수 둘도 정수로 나뉩니다. jsonb가 그 구별을 유지하기 때문입니다:

RETURN 7 / 2 AS integer_division, 7.0 / 2 AS real_division;
 integer_division |   real_division
------------------+--------------------
 3                | 3.5000000000000000

관련 항목#