Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1qhdYF-003inN-Jj for pgsql-hackers@arkaria.postgresql.org; Sat, 16 Sep 2023 22:14:07 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1qhdYD-001GEH-7H for pgsql-hackers@arkaria.postgresql.org; Sat, 16 Sep 2023 22:14:05 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1qhdYC-001GE8-OT for pgsql-hackers@lists.postgresql.org; Sat, 16 Sep 2023 22:14:04 +0000 Received: from mout-u-107.mailbox.org ([80.241.59.207]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1qhdY9-005Wzw-DE for pgsql-hackers@lists.postgresql.org; Sat, 16 Sep 2023 22:14:04 +0000 Received: from smtp202.mailbox.org (smtp202.mailbox.org [10.196.197.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-u-107.mailbox.org (Postfix) with ESMTPS id 4Rp51d3yZjz9sSP; Sun, 17 Sep 2023 00:13:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ewie.name; s=MBO0001; t=1694902437; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hZVuizGRyT+kDDPC8/4s5nd7p8AUy7xt6NC6qK05Qe8=; b=nkgtaOwaA06dh1ZJa44zZ8Y/KRUx9iebiUlaLgagN1egNAPmgXdP0pWLb5s6H2yQc1JcYY F/NLgzbQvI0eCpKJLlziNCq3v9TfQomWPgPbdR+NUXSDrRwWQGRkLRkG/EVAukuhDHLtZb 6L3s1/P1s936dmqEJpsHWd0Xg4jO6Jmt5NQGC6cfgDkgm5GnSm9irwE07yN5BauaMTRTEy L6vAMY2VuxRJebKbcxJSN8RKUIaNnIycSglVfKtEKqgnhoGOEhQmmGbtzJ5O3tALT9TfS5 uTRQRfkPWfN9S1x6bLChOAemkPDuN/MAah7snVu//a4IUx093pccrKqjOT+S/w== Date: Sun, 17 Sep 2023 00:13:56 +0200 (CEST) From: Erik Wienhold To: "David E. Wheeler" Cc: pgsql-hackers@lists.postgresql.org Message-ID: <1093370370.83403.1694902436862@office.mailbox.org> In-Reply-To: <7A19C6A6-DEB4-426D-BC6E-9F35A691E567@justatheory.com> References: <15DD78A5-B5C4-4332-ACFE-55723259C07F@justatheory.com> <133696180.303713.1694566807910@office.mailbox.org> <7A19C6A6-DEB4-426D-BC6E-9F35A691E567@justatheory.com> Subject: Re: JSON Path and GIN Questions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Priority: 3 Importance: Normal List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 16/09/2023 22:26 CEST David E. Wheeler wrote: > I=E2=80=99ve started work on this; there=E2=80=99s so much to learn! Here= =E2=80=99s a new example > that surprised me a bit. Using the GPS tracker example from the docs [1] > loaded into a `:json` psql variable, this output of this query makes perf= ect > sense to me: > > david=3D# select jsonb_path_query(:'json', '$.track.segments.location[*] = ? (@ < 14)'); > jsonb_path_query > ------------------ > 13.4034 > 13.2635 > > Because `[*]` selects all the values. This, however, I did not expect: > > david=3D# select jsonb_path_query(:'json', '$.track.segments.location ? (= @[*] < 14)'); > jsonb_path_query > ------------------ > 13.4034 > 13.2635 > (2 rows) > > I had expected it to return two single-value arrays, instead: > > [13.4034] > [13.2635] > > It appears that the filter expression is doing some sub-selection, too. > Is that expected? Looks like the effect of lax mode which may unwrap arrays when necessary [1= ]. The array unwrapping looks like the result of jsonb_array_elements(). It kinda works in strict mode: =09SELECT jsonb_path_query(:'json', 'strict $.track.segments[*].location ? = (@[*] < 14)'); =09 =09 jsonb_path_query =09----------------------- =09 [47.763, 13.4034] =09 [47.706, 13.2635] =09(2 rows) But it does not remove elements from the matching arrays. Which I don't ev= en expect here because the path specifies the location array as the object to = be returned. The filter expression then only decides whether to return the location array or not. Nowhere in the docs does it say that the filter expression itself removes any elements from a matched array. Here's a query that filter's out individual array elements. It's quite a mouthful (especially to preserve the order of array elements): =09WITH location AS ( =09 SELECT loc, row_number() OVER () AS array_num =09 FROM jsonb_path_query(:'json', 'strict $.track.segments[*].location') = loc =09), =09element AS ( =09 SELECT array_num, e.num AS elem_num, e.elem =09 FROM location =09 CROSS JOIN jsonb_array_elements(loc) WITH ORDINALITY AS e (elem, num= ) =09) =09SELECT jsonb_agg(elem ORDER BY elem_num) =09FROM element =09WHERE jsonb_path_exists(elem, '$ ? (@ < 14)') =09GROUP BY array_num; =09 =09 jsonb_agg =09--------------- =09 [13.2635] =09 [13.4034] =09(2 rows) [1] https://www.postgresql.org/docs/current/functions-json.html#STRICT-AND-= LAX-MODES -- Erik