O wiele bardziej efektywne byłoby przechowywanie wartości w znormalizowanym schemacie. To powiedziawszy, możesz również sprawić, aby działał z bieżącą konfiguracją.
Założenia
Zakładając tę definicję tabeli:
CREATE TABLE tbl (tbl_id int, usr jsonb);
„użytkownik” jest słowem zastrzeżonym i wymagałoby podwójnego cudzysłowu jako nazwy kolumny. Nie rób tego Używam usr
zamiast tego.
Pytanie
Zapytanie nie jest tak trywialne, jak się wydawało (teraz usunięte):
SELECT t.tbl_id, obj.val->>'count' AS count
FROM tbl t
JOIN LATERAL jsonb_array_elements(t.usr) obj(val) ON obj.val->>'_id' = '1'
WHERE t.usr @> '[{"_id":"1"}]';
Istnieją 3 podstawowe kroki :
1. Tanio identyfikuj kwalifikujące się rzędy
WHERE t.usr @> '[{"_id":"1"}]'
identyfikuje wiersze z pasującym obiektem w tablicy JSON. Wyrażenie może używać ogólnego indeksu GIN w jsonb
kolumnie lub indeksu z bardziej wyspecjalizowaną klasą operatora jsonb_path_ops
:
CREATE INDEX tbl_usr_gin_idx ON tbl USING gin (usr jsonb_path_ops);
Dodana WHERE
klauzula jest logicznie redundantna , ale wymagane jest użycie indeksu. Wyrażenie w klauzuli złączenia wymusza ten sam warunek, ale dopiero po odczekaniu tablicy w każdym kwalifikującym się wierszu. Dzięki obsłudze indeksu Postgres na początku przetwarza tylko wiersze zawierające kwalifikujący się obiekt. Nie ma większego znaczenia przy małych stołach, robi wielką różnicę przy dużych stołach i tylko kilku kwalifikujących się rzędach.
Związane z:
2. Zidentyfikuj pasujące obiekty w tablicy
Unnest with jsonb_array_elements()
. ( unnest()
jest dobry tylko dla typów tablic Postgres.) Ponieważ jesteśmy zainteresowani tylko dopasowaniem obiektów, od razu filtruj warunki łączenia.
Związane z:
3. Wyodrębnij wartość dla zagnieżdżonego klucza 'count'
Po kwalifikujących obiekty zostały wydobyte, po prostu: obj.val->>'count'
.
obj(value)
pochodzi? Czy to jest naLATERAL JOIN
,jsonb_array_elements
czy gdzieś indziej?JOIN LATERAL jsonb_array_elements(t.usr) obj(value) is short for JOIN LATERAL jsonb_array_elements(t.usr) AS obj(value)
i toobj(value)
jest alias tabeli i kolumny? W tym przykładzie, jeśliobj
jest to alias tabeli, do czego to jest alias? Zestaw wróciłjsonb_array_elements
?JOIN LATERAL jsonb_array_elements(t.usr) obj ON obj->>'_id' = '1'
miał ten sam efekt (po zaktualizowaniu instrukcji select do użyciavalue
zamiastval
). Wygląda na to, żejsonb_array_elements(t.usr)
zwraca tabelę z tylko jedną kolumną. Czy postgres jest inteligentny i zdaje sobie sprawę, żeobj ->>
to samo coobj.val ->>
?