From 723c092072cf5727990b08d5d3840c1a14599173 Mon Sep 17 00:00:00 2001 From: Stefano Ottolenghi Date: Tue, 23 Jul 2024 11:23:06 +0200 Subject: [PATCH 01/64] Update version to 5.23. --- antora.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/antora.yml b/antora.yml index 986c4d003..3efd4c638 100644 --- a/antora.yml +++ b/antora.yml @@ -7,5 +7,5 @@ nav: asciidoc: attributes: neo4j-version: '5' - neo4j-version-minor: '5.22' - neo4j-version-exact: '5.22.0' + neo4j-version-minor: '5.23' + neo4j-version-exact: '5.23.0' From 87a4ebfa980a9da039534375cbbfa199cc66ded9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:04:34 +0200 Subject: [PATCH 02/64] Bump the prod-dependencies group with 2 updates (#1001) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the prod-dependencies group with 2 updates: [@antora/cli](https://gitlab.com/antora/antora) and [@antora/site-generator-default](https://gitlab.com/antora/antora). Updates `@antora/cli` from 3.1.8 to 3.1.9
Changelog

Sourced from @​antora/cli's changelog.

== 3.1.9 (2024-07-05)

=== Changed

  • site-generator: Detect and warn when an AsciiDoc extension is registered as an Antora extension, but do no skip it (#1141)
  • Replace "AsciiDoc extension" with "Asciidoctor extension" in log messages

=== Fixed

  • file-publisher: Wrap legacy stream on file when preparing files for output providers; remove listeners limit (#1139)
Commits

Updates `@antora/site-generator-default` from 3.1.8 to 3.1.9
Changelog

Sourced from @​antora/site-generator-default's changelog.

== 3.1.9 (2024-07-05)

=== Changed

  • site-generator: Detect and warn when an AsciiDoc extension is registered as an Antora extension, but do no skip it (#1141)
  • Replace "AsciiDoc extension" with "Asciidoctor extension" in log messages

=== Fixed

  • file-publisher: Wrap legacy stream on file when preparing files for output providers; remove listeners limit (#1139)
Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 320 +++++++++++++++++++++++----------------------- package.json | 4 +- 2 files changed, 162 insertions(+), 162 deletions(-) diff --git a/package-lock.json b/package-lock.json index 74567389f..73be5181f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,8 @@ "version": "5.0.0", "license": "ISC", "dependencies": { - "@antora/cli": "^3.1.8", - "@antora/site-generator-default": "^3.1.8", + "@antora/cli": "^3.1.9", + "@antora/site-generator-default": "^3.1.9", "@neo4j-antora/antora-add-notes": "^0.3.1", "@neo4j-antora/antora-modify-sitemaps": "^0.4.4", "@neo4j-antora/antora-page-roles": "^0.3.1", @@ -26,11 +26,11 @@ } }, "node_modules/@antora/asciidoc-loader": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/asciidoc-loader/-/asciidoc-loader-3.1.8.tgz", - "integrity": "sha512-tNa9YBA/wVA3RGmDhAF2i4s7TPWgMcZsKZF1+mFBiYmhVuIiI5mkp6sH2M+/8MlApydSOc8p375gudgLKPKrJw==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/asciidoc-loader/-/asciidoc-loader-3.1.9.tgz", + "integrity": "sha512-flE27T2yI8TX7rUNjbBHWN3iR6s+kBuRBbUPncUFcWjx6mXzll8JLiTkxnc8JXHGzgKlveT+t5AkPYGACLfasg==", "dependencies": { - "@antora/logger": "3.1.8", + "@antora/logger": "3.1.9", "@antora/user-require-helper": "~2.0", "@asciidoctor/core": "~2.2" }, @@ -39,12 +39,12 @@ } }, "node_modules/@antora/cli": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/cli/-/cli-3.1.8.tgz", - "integrity": "sha512-V7oIbbAONovCQWX2tKG14YmX03p6tquLP753NJEjj7QXjiWmJhOI0JsTD+fvaXr7DzkDnjnls4OwFBmiHZIkOw==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/cli/-/cli-3.1.9.tgz", + "integrity": "sha512-kCUqWX3G/9Pvf8SWZ45ioHwWdOc9uamy2E5/FFwyGiTeu4ubNbadOauLVvMzSZHUxVDnGxXwCsmmQ2HwM919ew==", "dependencies": { - "@antora/logger": "3.1.8", - "@antora/playbook-builder": "3.1.8", + "@antora/logger": "3.1.9", + "@antora/playbook-builder": "3.1.9", "@antora/user-require-helper": "~2.0", "commander": "~11.1" }, @@ -56,12 +56,12 @@ } }, "node_modules/@antora/content-aggregator": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/content-aggregator/-/content-aggregator-3.1.8.tgz", - "integrity": "sha512-xBWbw2fiQ6UMEIGzknvpDLUW0gTpyiQVaRXjAOYe0JDAAvifjt0uJuBsu7WrRe1FmRkfkrYj8BJ6Yv34NWZJuA==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/content-aggregator/-/content-aggregator-3.1.9.tgz", + "integrity": "sha512-g+UzevPSm5c4R0j1U9uysJfdIUfp++QOHIEBmqjhfx/aIEnOL70zA+WF55Mm+syAfzU3877puI27sOp8qtPglw==", "dependencies": { "@antora/expand-path-helper": "~2.0", - "@antora/logger": "3.1.8", + "@antora/logger": "3.1.9", "@antora/user-require-helper": "~2.0", "braces": "~3.0", "cache-directory": "~2.0", @@ -92,12 +92,12 @@ } }, "node_modules/@antora/content-classifier": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/content-classifier/-/content-classifier-3.1.8.tgz", - "integrity": "sha512-0EzsZl7oBR5/MzLGIo3WwFeub2YtyDqExrELDmyDcJ4opZMREWfgUFu5Kls1MFAQPSbzEmQyIdyGacOrwTQHrg==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/content-classifier/-/content-classifier-3.1.9.tgz", + "integrity": "sha512-PVJqwp5uvZE1PlpeJtb0p6al75fN+fmXGIC6DHcKysRnr0xo+sgz8X2r4mnNWdTWRqum2yVigMmmuXYTg3cJlQ==", "dependencies": { - "@antora/asciidoc-loader": "3.1.8", - "@antora/logger": "3.1.8", + "@antora/asciidoc-loader": "3.1.9", + "@antora/logger": "3.1.9", "mime-types": "~2.1", "vinyl": "~3.0" }, @@ -106,11 +106,11 @@ } }, "node_modules/@antora/document-converter": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/document-converter/-/document-converter-3.1.8.tgz", - "integrity": "sha512-dUGqgSdWnJYigbPZ9mDcoxITnufOEF5Vb5DKUxEstXe6MMn0yTZ03jJUbLs5YFgjqjhyULDMMIPo6no55zvx+w==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/document-converter/-/document-converter-3.1.9.tgz", + "integrity": "sha512-pH7tQaIjcPsFdYkaBEAvA/5ki04IQwQGHoR+2jadKdMl6P+J5KA1VzNnMgyIL6gHn7auJIkoOKadfItRB9lHGQ==", "dependencies": { - "@antora/asciidoc-loader": "3.1.8" + "@antora/asciidoc-loader": "3.1.9" }, "engines": { "node": ">=16.0.0" @@ -125,9 +125,9 @@ } }, "node_modules/@antora/file-publisher": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/file-publisher/-/file-publisher-3.1.8.tgz", - "integrity": "sha512-crVP9EF5NZJDzeYPSpy74x35GRJIa4PfjfYBUxhzoNfqgX3JZcNuP8IwsWrSNyBDGO9a7ZCQ7+p4kpnVpF2x8Q==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/file-publisher/-/file-publisher-3.1.9.tgz", + "integrity": "sha512-C0VwVjuFbE1CVpZDgwYR1gZCNr1tMw5vueyF9wHZH0KCqAsp9iwo7bwj8wKWMPogxcxdYhnAvtDJnYmYFCuDWQ==", "dependencies": { "@antora/expand-path-helper": "~2.0", "@antora/user-require-helper": "~2.0", @@ -139,9 +139,9 @@ } }, "node_modules/@antora/logger": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/logger/-/logger-3.1.8.tgz", - "integrity": "sha512-zbfjB1oMDDuuHjiRnBIbVTUBW1l1hCHbK4Q1oIRujnSz2LLjyY/aZfvgwODpREBGmvjkFb6Dlc9VUkKObQKi7g==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/logger/-/logger-3.1.9.tgz", + "integrity": "sha512-MKuANodcX0lfRyiB+Rxl/Kv7UOxc2glzTYFoIoBB7uzxF0A+AhvUJDmpGQFRFN2ihxy99N3nLJmZpDebwXyE+A==", "dependencies": { "@antora/expand-path-helper": "~2.0", "pino": "~9.2", @@ -153,22 +153,22 @@ } }, "node_modules/@antora/navigation-builder": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/navigation-builder/-/navigation-builder-3.1.8.tgz", - "integrity": "sha512-u/USiJ1HhKSUxfUtLv7aQBFCJfBz6RtdzapKIy4z2Wol0FrwQwdaUhv7Amzabi2nrPEzkaNAM6ZX7iNPjGOw6Q==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/navigation-builder/-/navigation-builder-3.1.9.tgz", + "integrity": "sha512-zyl2yNjK31Dl6TRJgnoFb4Czwt9ar3wLTycAdMeZ+U/8YcAUHD8z7NCssPFFvZ0BbUr00NP+gbqDmCr6yz32NQ==", "dependencies": { - "@antora/asciidoc-loader": "3.1.8" + "@antora/asciidoc-loader": "3.1.9" }, "engines": { "node": ">=16.0.0" } }, "node_modules/@antora/page-composer": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/page-composer/-/page-composer-3.1.8.tgz", - "integrity": "sha512-dw1ECMLYdf9GC9Zj8sHPd9Fgcg6BjU5BDbP+HI4omtOhLUiBVwWL1lZwFRVwgGMDgKSVgnxd9yotk+WTy2iLEg==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/page-composer/-/page-composer-3.1.9.tgz", + "integrity": "sha512-X6Qj+J5dfFAGXoCAOaA+R6xRp8UoNMDHsRsB1dUTT2QNzk1Lrq6YkYyljdD2cxkWjLVqQ/pQSP+BJVNFGbqDAQ==", "dependencies": { - "@antora/logger": "3.1.8", + "@antora/logger": "3.1.9", "handlebars": "~4.7", "require-from-string": "~2.0" }, @@ -177,9 +177,9 @@ } }, "node_modules/@antora/playbook-builder": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/playbook-builder/-/playbook-builder-3.1.8.tgz", - "integrity": "sha512-VDIP8cVnmyRcbg4orP2mE8HkqHTh7MRE+QyJ8XyHvFZsZjcS0Qw5UqPcrlmqXrzQKmJcBj2plqSv+wKXAYbNcQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/playbook-builder/-/playbook-builder-3.1.9.tgz", + "integrity": "sha512-MJ/OWz4pReC98nygGTXC5bOL/TDDtCYpSkHFBz2ST4L6tuM8rv9c5+cp//JkwY/QlTOvcuJ0f2xq4a7a5nI7Qw==", "dependencies": { "@iarna/toml": "~2.2", "convict": "~6.2", @@ -191,9 +191,9 @@ } }, "node_modules/@antora/redirect-producer": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/redirect-producer/-/redirect-producer-3.1.8.tgz", - "integrity": "sha512-ZSRnK/rXZ715baFheXMWEsyz0BpR+6RxFAem8A7rZPt2HMMKCOiuaFNdf9C97dxU5FxSELBIkRpqQ7eTRk+PPA==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/redirect-producer/-/redirect-producer-3.1.9.tgz", + "integrity": "sha512-9OLwoMhqifsBxTebInh/5W16GdDsdj+YkKG3TiCASlAOYsDbuhbeRPFUlyKKSRkMrtKKnFgHR0Z3DNPXYlH2NQ==", "dependencies": { "vinyl": "~3.0" }, @@ -202,23 +202,23 @@ } }, "node_modules/@antora/site-generator": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/site-generator/-/site-generator-3.1.8.tgz", - "integrity": "sha512-xy1aUxTsCiC/KPlKQIoj2VWK956Mal8YyeokqXQTlTfRkuT5LPTJdmTA1ZHMEY9INy0z01Jx56Uyns62q98UtQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/site-generator/-/site-generator-3.1.9.tgz", + "integrity": "sha512-YYESPG22tGX1CxRPSAr6acKILCO8JfGkM1OYc7Sw3D7ZvCy1YgZMAaTYK0T5yl9LXg+l/UZi1xq/Ej0qHnYQiw==", "dependencies": { - "@antora/asciidoc-loader": "3.1.8", - "@antora/content-aggregator": "3.1.8", - "@antora/content-classifier": "3.1.8", - "@antora/document-converter": "3.1.8", - "@antora/file-publisher": "3.1.8", - "@antora/logger": "3.1.8", - "@antora/navigation-builder": "3.1.8", - "@antora/page-composer": "3.1.8", - "@antora/playbook-builder": "3.1.8", - "@antora/redirect-producer": "3.1.8", - "@antora/site-mapper": "3.1.8", - "@antora/site-publisher": "3.1.8", - "@antora/ui-loader": "3.1.8", + "@antora/asciidoc-loader": "3.1.9", + "@antora/content-aggregator": "3.1.9", + "@antora/content-classifier": "3.1.9", + "@antora/document-converter": "3.1.9", + "@antora/file-publisher": "3.1.9", + "@antora/logger": "3.1.9", + "@antora/navigation-builder": "3.1.9", + "@antora/page-composer": "3.1.9", + "@antora/playbook-builder": "3.1.9", + "@antora/redirect-producer": "3.1.9", + "@antora/site-mapper": "3.1.9", + "@antora/site-publisher": "3.1.9", + "@antora/ui-loader": "3.1.9", "@antora/user-require-helper": "~2.0" }, "engines": { @@ -226,22 +226,22 @@ } }, "node_modules/@antora/site-generator-default": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/site-generator-default/-/site-generator-default-3.1.8.tgz", - "integrity": "sha512-6cjgxatANsp4iTbX6gbadfWwYngH4EXG3AyFWOmf6jMRih2MQSGc9zYL+QfHP6uqUiBfhIPCFwLbh3IiQ1v8JQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/site-generator-default/-/site-generator-default-3.1.9.tgz", + "integrity": "sha512-m/QCv2o/24VmWZaeqtc6nNEky///GTLLx/pyyihP7uWKvZ0AhGPp6Agv1yaShjKIthBzHJ3JozaMPev2leor+A==", "dependencies": { - "@antora/site-generator": "3.1.8" + "@antora/site-generator": "3.1.9" }, "engines": { "node": ">=16.0.0" } }, "node_modules/@antora/site-mapper": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/site-mapper/-/site-mapper-3.1.8.tgz", - "integrity": "sha512-RV6SRiNFDd/dQRXvsckTsFQIiEpH7rHIoKlsOFB261rRY4JhXSu21TjR0dpk2vJ6iPMyudIuTkwoTWsdDi389Q==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/site-mapper/-/site-mapper-3.1.9.tgz", + "integrity": "sha512-9FCObL+JIjBoby8z+beu2uuvAtCjm5EsEQt+16gCIMX1ktVP3W3gVsdRSvVcGcVEpizILFhMawkcQknZPUp5mg==", "dependencies": { - "@antora/content-classifier": "3.1.8", + "@antora/content-classifier": "3.1.9", "vinyl": "~3.0" }, "engines": { @@ -249,20 +249,20 @@ } }, "node_modules/@antora/site-publisher": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/site-publisher/-/site-publisher-3.1.8.tgz", - "integrity": "sha512-DdC+IDdzeYlmTu+LwMZ24hFJJRU+f8WG2MjM7kvKQ8fkPdk0TdzNoq3TkH78sYd+2WYXKuQU6DFU/OPxY44ulA==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/site-publisher/-/site-publisher-3.1.9.tgz", + "integrity": "sha512-L5To8f4QswZliXu6yB6O7O8CuBbLctjNbxZqP3m0FP7VaOONp85ftzEq1BFEm4BXXSwH1n4ujZx1qGBHP9ooOQ==", "dependencies": { - "@antora/file-publisher": "3.1.8" + "@antora/file-publisher": "3.1.9" }, "engines": { "node": ">=16.0.0" } }, "node_modules/@antora/ui-loader": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/ui-loader/-/ui-loader-3.1.8.tgz", - "integrity": "sha512-wiStSKnt+QGTeVRpnM9fxOUf1xxyB4Y3cgRgdi5hb291pG/izz8imh3csjgMwN2jB3zZD4qYSJ29xnGr4+pK8Q==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/ui-loader/-/ui-loader-3.1.9.tgz", + "integrity": "sha512-g0/9dRE5JVMYukIU3x+Rvr41bPdK3sUD2xQIAniRjE6usIZs1mEsTGshVKVEoOqqnSekXE85HVhybjNHsC+qbQ==", "dependencies": { "@antora/expand-path-helper": "~2.0", "braces": "~3.0", @@ -2354,9 +2354,9 @@ } }, "node_modules/text-decoder": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", - "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", + "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", "dependencies": { "b4a": "^1.6.4" } @@ -2415,9 +2415,9 @@ } }, "node_modules/uglify-js": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.18.0.tgz", - "integrity": "sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==", + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.1.tgz", + "integrity": "sha512-y/2wiW+ceTYR2TSSptAhfnEtpLaQ4Ups5zrjB2d3kuVxHj16j/QJwPl5PvuGy9uARb39J0+iKxcRPvtpsx4A4A==", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -2542,33 +2542,33 @@ }, "dependencies": { "@antora/asciidoc-loader": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/asciidoc-loader/-/asciidoc-loader-3.1.8.tgz", - "integrity": "sha512-tNa9YBA/wVA3RGmDhAF2i4s7TPWgMcZsKZF1+mFBiYmhVuIiI5mkp6sH2M+/8MlApydSOc8p375gudgLKPKrJw==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/asciidoc-loader/-/asciidoc-loader-3.1.9.tgz", + "integrity": "sha512-flE27T2yI8TX7rUNjbBHWN3iR6s+kBuRBbUPncUFcWjx6mXzll8JLiTkxnc8JXHGzgKlveT+t5AkPYGACLfasg==", "requires": { - "@antora/logger": "3.1.8", + "@antora/logger": "3.1.9", "@antora/user-require-helper": "~2.0", "@asciidoctor/core": "~2.2" } }, "@antora/cli": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/cli/-/cli-3.1.8.tgz", - "integrity": "sha512-V7oIbbAONovCQWX2tKG14YmX03p6tquLP753NJEjj7QXjiWmJhOI0JsTD+fvaXr7DzkDnjnls4OwFBmiHZIkOw==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/cli/-/cli-3.1.9.tgz", + "integrity": "sha512-kCUqWX3G/9Pvf8SWZ45ioHwWdOc9uamy2E5/FFwyGiTeu4ubNbadOauLVvMzSZHUxVDnGxXwCsmmQ2HwM919ew==", "requires": { - "@antora/logger": "3.1.8", - "@antora/playbook-builder": "3.1.8", + "@antora/logger": "3.1.9", + "@antora/playbook-builder": "3.1.9", "@antora/user-require-helper": "~2.0", "commander": "~11.1" } }, "@antora/content-aggregator": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/content-aggregator/-/content-aggregator-3.1.8.tgz", - "integrity": "sha512-xBWbw2fiQ6UMEIGzknvpDLUW0gTpyiQVaRXjAOYe0JDAAvifjt0uJuBsu7WrRe1FmRkfkrYj8BJ6Yv34NWZJuA==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/content-aggregator/-/content-aggregator-3.1.9.tgz", + "integrity": "sha512-g+UzevPSm5c4R0j1U9uysJfdIUfp++QOHIEBmqjhfx/aIEnOL70zA+WF55Mm+syAfzU3877puI27sOp8qtPglw==", "requires": { "@antora/expand-path-helper": "~2.0", - "@antora/logger": "3.1.8", + "@antora/logger": "3.1.9", "@antora/user-require-helper": "~2.0", "braces": "~3.0", "cache-directory": "~2.0", @@ -2592,22 +2592,22 @@ } }, "@antora/content-classifier": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/content-classifier/-/content-classifier-3.1.8.tgz", - "integrity": "sha512-0EzsZl7oBR5/MzLGIo3WwFeub2YtyDqExrELDmyDcJ4opZMREWfgUFu5Kls1MFAQPSbzEmQyIdyGacOrwTQHrg==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/content-classifier/-/content-classifier-3.1.9.tgz", + "integrity": "sha512-PVJqwp5uvZE1PlpeJtb0p6al75fN+fmXGIC6DHcKysRnr0xo+sgz8X2r4mnNWdTWRqum2yVigMmmuXYTg3cJlQ==", "requires": { - "@antora/asciidoc-loader": "3.1.8", - "@antora/logger": "3.1.8", + "@antora/asciidoc-loader": "3.1.9", + "@antora/logger": "3.1.9", "mime-types": "~2.1", "vinyl": "~3.0" } }, "@antora/document-converter": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/document-converter/-/document-converter-3.1.8.tgz", - "integrity": "sha512-dUGqgSdWnJYigbPZ9mDcoxITnufOEF5Vb5DKUxEstXe6MMn0yTZ03jJUbLs5YFgjqjhyULDMMIPo6no55zvx+w==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/document-converter/-/document-converter-3.1.9.tgz", + "integrity": "sha512-pH7tQaIjcPsFdYkaBEAvA/5ki04IQwQGHoR+2jadKdMl6P+J5KA1VzNnMgyIL6gHn7auJIkoOKadfItRB9lHGQ==", "requires": { - "@antora/asciidoc-loader": "3.1.8" + "@antora/asciidoc-loader": "3.1.9" } }, "@antora/expand-path-helper": { @@ -2616,9 +2616,9 @@ "integrity": "sha512-CSMBGC+tI21VS2kGW3PV7T2kQTM5eT3f2GTPVLttwaNYbNxDve08en/huzszHJfxo11CcEs26Ostr0F2c1QqeA==" }, "@antora/file-publisher": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/file-publisher/-/file-publisher-3.1.8.tgz", - "integrity": "sha512-crVP9EF5NZJDzeYPSpy74x35GRJIa4PfjfYBUxhzoNfqgX3JZcNuP8IwsWrSNyBDGO9a7ZCQ7+p4kpnVpF2x8Q==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/file-publisher/-/file-publisher-3.1.9.tgz", + "integrity": "sha512-C0VwVjuFbE1CVpZDgwYR1gZCNr1tMw5vueyF9wHZH0KCqAsp9iwo7bwj8wKWMPogxcxdYhnAvtDJnYmYFCuDWQ==", "requires": { "@antora/expand-path-helper": "~2.0", "@antora/user-require-helper": "~2.0", @@ -2627,9 +2627,9 @@ } }, "@antora/logger": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/logger/-/logger-3.1.8.tgz", - "integrity": "sha512-zbfjB1oMDDuuHjiRnBIbVTUBW1l1hCHbK4Q1oIRujnSz2LLjyY/aZfvgwODpREBGmvjkFb6Dlc9VUkKObQKi7g==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/logger/-/logger-3.1.9.tgz", + "integrity": "sha512-MKuANodcX0lfRyiB+Rxl/Kv7UOxc2glzTYFoIoBB7uzxF0A+AhvUJDmpGQFRFN2ihxy99N3nLJmZpDebwXyE+A==", "requires": { "@antora/expand-path-helper": "~2.0", "pino": "~9.2", @@ -2638,27 +2638,27 @@ } }, "@antora/navigation-builder": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/navigation-builder/-/navigation-builder-3.1.8.tgz", - "integrity": "sha512-u/USiJ1HhKSUxfUtLv7aQBFCJfBz6RtdzapKIy4z2Wol0FrwQwdaUhv7Amzabi2nrPEzkaNAM6ZX7iNPjGOw6Q==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/navigation-builder/-/navigation-builder-3.1.9.tgz", + "integrity": "sha512-zyl2yNjK31Dl6TRJgnoFb4Czwt9ar3wLTycAdMeZ+U/8YcAUHD8z7NCssPFFvZ0BbUr00NP+gbqDmCr6yz32NQ==", "requires": { - "@antora/asciidoc-loader": "3.1.8" + "@antora/asciidoc-loader": "3.1.9" } }, "@antora/page-composer": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/page-composer/-/page-composer-3.1.8.tgz", - "integrity": "sha512-dw1ECMLYdf9GC9Zj8sHPd9Fgcg6BjU5BDbP+HI4omtOhLUiBVwWL1lZwFRVwgGMDgKSVgnxd9yotk+WTy2iLEg==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/page-composer/-/page-composer-3.1.9.tgz", + "integrity": "sha512-X6Qj+J5dfFAGXoCAOaA+R6xRp8UoNMDHsRsB1dUTT2QNzk1Lrq6YkYyljdD2cxkWjLVqQ/pQSP+BJVNFGbqDAQ==", "requires": { - "@antora/logger": "3.1.8", + "@antora/logger": "3.1.9", "handlebars": "~4.7", "require-from-string": "~2.0" } }, "@antora/playbook-builder": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/playbook-builder/-/playbook-builder-3.1.8.tgz", - "integrity": "sha512-VDIP8cVnmyRcbg4orP2mE8HkqHTh7MRE+QyJ8XyHvFZsZjcS0Qw5UqPcrlmqXrzQKmJcBj2plqSv+wKXAYbNcQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/playbook-builder/-/playbook-builder-3.1.9.tgz", + "integrity": "sha512-MJ/OWz4pReC98nygGTXC5bOL/TDDtCYpSkHFBz2ST4L6tuM8rv9c5+cp//JkwY/QlTOvcuJ0f2xq4a7a5nI7Qw==", "requires": { "@iarna/toml": "~2.2", "convict": "~6.2", @@ -2667,63 +2667,63 @@ } }, "@antora/redirect-producer": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/redirect-producer/-/redirect-producer-3.1.8.tgz", - "integrity": "sha512-ZSRnK/rXZ715baFheXMWEsyz0BpR+6RxFAem8A7rZPt2HMMKCOiuaFNdf9C97dxU5FxSELBIkRpqQ7eTRk+PPA==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/redirect-producer/-/redirect-producer-3.1.9.tgz", + "integrity": "sha512-9OLwoMhqifsBxTebInh/5W16GdDsdj+YkKG3TiCASlAOYsDbuhbeRPFUlyKKSRkMrtKKnFgHR0Z3DNPXYlH2NQ==", "requires": { "vinyl": "~3.0" } }, "@antora/site-generator": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/site-generator/-/site-generator-3.1.8.tgz", - "integrity": "sha512-xy1aUxTsCiC/KPlKQIoj2VWK956Mal8YyeokqXQTlTfRkuT5LPTJdmTA1ZHMEY9INy0z01Jx56Uyns62q98UtQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/site-generator/-/site-generator-3.1.9.tgz", + "integrity": "sha512-YYESPG22tGX1CxRPSAr6acKILCO8JfGkM1OYc7Sw3D7ZvCy1YgZMAaTYK0T5yl9LXg+l/UZi1xq/Ej0qHnYQiw==", "requires": { - "@antora/asciidoc-loader": "3.1.8", - "@antora/content-aggregator": "3.1.8", - "@antora/content-classifier": "3.1.8", - "@antora/document-converter": "3.1.8", - "@antora/file-publisher": "3.1.8", - "@antora/logger": "3.1.8", - "@antora/navigation-builder": "3.1.8", - "@antora/page-composer": "3.1.8", - "@antora/playbook-builder": "3.1.8", - "@antora/redirect-producer": "3.1.8", - "@antora/site-mapper": "3.1.8", - "@antora/site-publisher": "3.1.8", - "@antora/ui-loader": "3.1.8", + "@antora/asciidoc-loader": "3.1.9", + "@antora/content-aggregator": "3.1.9", + "@antora/content-classifier": "3.1.9", + "@antora/document-converter": "3.1.9", + "@antora/file-publisher": "3.1.9", + "@antora/logger": "3.1.9", + "@antora/navigation-builder": "3.1.9", + "@antora/page-composer": "3.1.9", + "@antora/playbook-builder": "3.1.9", + "@antora/redirect-producer": "3.1.9", + "@antora/site-mapper": "3.1.9", + "@antora/site-publisher": "3.1.9", + "@antora/ui-loader": "3.1.9", "@antora/user-require-helper": "~2.0" } }, "@antora/site-generator-default": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/site-generator-default/-/site-generator-default-3.1.8.tgz", - "integrity": "sha512-6cjgxatANsp4iTbX6gbadfWwYngH4EXG3AyFWOmf6jMRih2MQSGc9zYL+QfHP6uqUiBfhIPCFwLbh3IiQ1v8JQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/site-generator-default/-/site-generator-default-3.1.9.tgz", + "integrity": "sha512-m/QCv2o/24VmWZaeqtc6nNEky///GTLLx/pyyihP7uWKvZ0AhGPp6Agv1yaShjKIthBzHJ3JozaMPev2leor+A==", "requires": { - "@antora/site-generator": "3.1.8" + "@antora/site-generator": "3.1.9" } }, "@antora/site-mapper": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/site-mapper/-/site-mapper-3.1.8.tgz", - "integrity": "sha512-RV6SRiNFDd/dQRXvsckTsFQIiEpH7rHIoKlsOFB261rRY4JhXSu21TjR0dpk2vJ6iPMyudIuTkwoTWsdDi389Q==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/site-mapper/-/site-mapper-3.1.9.tgz", + "integrity": "sha512-9FCObL+JIjBoby8z+beu2uuvAtCjm5EsEQt+16gCIMX1ktVP3W3gVsdRSvVcGcVEpizILFhMawkcQknZPUp5mg==", "requires": { - "@antora/content-classifier": "3.1.8", + "@antora/content-classifier": "3.1.9", "vinyl": "~3.0" } }, "@antora/site-publisher": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/site-publisher/-/site-publisher-3.1.8.tgz", - "integrity": "sha512-DdC+IDdzeYlmTu+LwMZ24hFJJRU+f8WG2MjM7kvKQ8fkPdk0TdzNoq3TkH78sYd+2WYXKuQU6DFU/OPxY44ulA==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/site-publisher/-/site-publisher-3.1.9.tgz", + "integrity": "sha512-L5To8f4QswZliXu6yB6O7O8CuBbLctjNbxZqP3m0FP7VaOONp85ftzEq1BFEm4BXXSwH1n4ujZx1qGBHP9ooOQ==", "requires": { - "@antora/file-publisher": "3.1.8" + "@antora/file-publisher": "3.1.9" } }, "@antora/ui-loader": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@antora/ui-loader/-/ui-loader-3.1.8.tgz", - "integrity": "sha512-wiStSKnt+QGTeVRpnM9fxOUf1xxyB4Y3cgRgdi5hb291pG/izz8imh3csjgMwN2jB3zZD4qYSJ29xnGr4+pK8Q==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@antora/ui-loader/-/ui-loader-3.1.9.tgz", + "integrity": "sha512-g0/9dRE5JVMYukIU3x+Rvr41bPdK3sUD2xQIAniRjE6usIZs1mEsTGshVKVEoOqqnSekXE85HVhybjNHsC+qbQ==", "requires": { "@antora/expand-path-helper": "~2.0", "braces": "~3.0", @@ -4240,9 +4240,9 @@ } }, "text-decoder": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", - "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", + "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", "requires": { "b4a": "^1.6.4" } @@ -4289,9 +4289,9 @@ } }, "uglify-js": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.18.0.tgz", - "integrity": "sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==", + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.1.tgz", + "integrity": "sha512-y/2wiW+ceTYR2TSSptAhfnEtpLaQ4Ups5zrjB2d3kuVxHj16j/QJwPl5PvuGy9uARb39J0+iKxcRPvtpsx4A4A==", "optional": true }, "undefsafe": { diff --git a/package.json b/package.json index 9bcea5a76..624ebb8c1 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "author": "Neo4j", "license": "ISC", "dependencies": { - "@antora/cli": "^3.1.8", - "@antora/site-generator-default": "^3.1.8", + "@antora/cli": "^3.1.9", + "@antora/site-generator-default": "^3.1.9", "@neo4j-antora/antora-add-notes": "^0.3.1", "@neo4j-antora/antora-modify-sitemaps": "^0.4.4", "@neo4j-antora/antora-page-roles": "^0.3.1", From 5af21500e41ecc25ea178d41fc004998b255dd0d Mon Sep 17 00:00:00 2001 From: Gem Lamont <106068376+gem-neo4j@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:24:57 +0200 Subject: [PATCH 03/64] Add TIME ZONE alias (#1010) GQL additionally allows for TIME ZONE (Not TIMEZONE like we currently have) --- .../pages/appendix/gql-conformance/index.adoc | 2 +- ...ions-additions-removals-compatibility.adoc | 23 +++++++++++++++++++ .../property-structural-constructed.adoc | 8 +++---- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/appendix/gql-conformance/index.adoc b/modules/ROOT/pages/appendix/gql-conformance/index.adoc index 4c4da7984..2bc52908d 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/index.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/index.adoc @@ -42,5 +42,5 @@ Neo4j 5.14 added support for JavaSE 21 and version 15 of the Unicode Standard. For more information, see xref:syntax/parsing.adoc##_using_unicodes_in_cypher[Parsing -> Using Unicode in Cypher]. * Cypher supports the following mandatory GQL property types: `BOOLEAN` (`BOOL`), `FLOAT` footnote:[The `FLOAT` type in Cypher always represents a 64-bit double-precision floating point number.], `INTEGER` (`SIGNED INTEGER`, or `INT`)footnote:[The `INTEGER` type in Cypher always represents a 64-bit `INTEGER`.], and `STRING` (`VARCHAR`). + -Cypher also supports the following optional GQL property types: `DATE`, `DURATION`, `LIST` (`ARRAY`, `INNER_TYPE LIST`, or `INNER_TYPE ARRAY`)footnote:[The `INNER_TYPE` cannot be a `LIST` type.], `LOCAL DATETIME` (`TIMESTAMP WITHOUT TIMEZONE`), `LOCAL TIME` (`TIME WITHOUT TIME ZONE`), `POINT`, `ZONED DATETIME` (`TIME WITH TIMEZONE`), and `ZONED TIME` (`TIMESTAMP WITH TIMEZONE`). +Cypher also supports the following optional GQL property types: `DATE`, `DURATION`, `LIST` (`ARRAY`, `INNER_TYPE LIST`, or `INNER_TYPE ARRAY`)footnote:[The `INNER_TYPE` cannot be a `LIST` type.], `LOCAL DATETIME` (`TIMESTAMP WITHOUT TIME ZONE`), `LOCAL TIME` (`TIME WITHOUT TIME ZONE`), `POINT`, `ZONED DATETIME` (`TIME WITH TIME ZONE`), and `ZONED TIME` (`TIMESTAMP WITH TIME ZONE`). For more information, see xref:values-and-types/property-structural-constructed.adoc#_property_types[Values and types -> property types]. diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index a815e56db..62109c01f 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -16,6 +16,29 @@ New features are added to the language continuously, and occasionally, some feat This section lists all of the features that have been removed, deprecated, added, or extended in different Cypher versions. Replacement syntax for deprecated and removed features are also indicated. +[[cypher-deprecations-additions-removals-5.23]] +== Neo4j 5.23 + +=== Updated features + +[cols="2", options="header"] +|=== +| Feature +| Details + +a| +label:functionality[] +label:updated[] +[source, cypher, role="noheader"] +---- +RETURN datetime.statement() IS :: TIMESTAMP WITH TIME ZONE +---- +a| +Introduced new GQL conformant aliases to duration types: `TIMESTAMP WITHOUT TIME ZONE` (alias to `LOCAL DATETIME`), `TIME WITHOUT TIME ZONE` (alias to `LOCAL TIME`), `TIMESTAMP WITH TIME ZONE` (alias to `ZONED DATETIME`), and `TIME WITH TIME ZONE` (alias to `ZONED TIME`). + +See xref::values-and-types/property-structural-constructed.adoc#types-synonyms[types and their synonyms] for more. +|=== + [[cypher-deprecations-additions-removals-5.21]] == Neo4j 5.21 diff --git a/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc b/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc index 1f3841496..618ade925 100644 --- a/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc +++ b/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc @@ -89,8 +89,8 @@ However, not all types can be used in all places. | `FLOAT` | | `INTEGER` | `INT`, `SIGNED INTEGER` | `LIST` | `ARRAY`, `INNER_TYPE LIST`, `INNER_TYPE ARRAY` -| `LOCAL DATETIME` | `TIMESTAMP WITHOUT TIMEZONE` -| `LOCAL TIME` | `TIME WITHOUT TIMEZONE` +| `LOCAL DATETIME` | `TIMESTAMP WITHOUT TIME ZONE`, `TIMESTAMP WITHOUT TIMEZONE` +| `LOCAL TIME` | `TIME WITHOUT TIME ZONE`, `TIME WITHOUT TIMEZONE` | `MAP` | | `NODE` | `ANY NODE`, `VERTEX`, `ANY VERTEX` | `NOTHING` | @@ -100,8 +100,8 @@ However, not all types can be used in all places. | `PROPERTY VALUE` | `ANY PROPERTY VALUE` | `RELATIONSHIP` | `ANY RELATIONSHIP`, `EDGE`, `ANY EDGE` | `STRING` | `VARCHAR` -| `ZONED DATETIME` | `TIMESTAMP WITH TIMEZONE` -| `ZONED TIME` | `TIME WITH TIMEZONE` +| `ZONED DATETIME` | `TIMESTAMP WITH TIME ZONE`, `TIMESTAMP WITH TIMEZONE` +| `ZONED TIME` | `TIME WITH TIME ZONE`, `TIME WITH TIMEZONE` | `INNER_TYPE_1 \| INNER_TYPE_2...` | `ANY` |=== From 1044a9da74fb91f9a9a2ce5498f622b9b5da287c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Mon, 5 Aug 2024 15:58:30 +0200 Subject: [PATCH 04/64] Fix result format of relationships function (#1011) --- modules/ROOT/pages/functions/list.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/functions/list.adoc b/modules/ROOT/pages/functions/list.adoc index c7ae65b69..b118c9d60 100644 --- a/modules/ROOT/pages/functions/list.adoc +++ b/modules/ROOT/pages/functions/list.adoc @@ -424,8 +424,8 @@ A `LIST` containing all the `RELATIONSHIP` values in the `PATH` `p [role="queryresult",options="header,footer",cols="1* Date: Thu, 8 Aug 2024 14:17:36 +0200 Subject: [PATCH 05/64] Document Variable Scope Clause (#990) --- modules/ROOT/images/call_subquery_graph.svg | 10 +- .../pages/appendix/gql-conformance/index.adoc | 4 +- .../gql-conformance/supported-mandatory.adoc | 2 +- .../gql-conformance/supported-optional.adoc | 8 + modules/ROOT/pages/clauses/load-csv.adoc | 7 +- ...ions-additions-removals-compatibility.adoc | 48 ++ modules/ROOT/pages/genai-integrations.adoc | 7 +- .../ROOT/pages/patterns/shortest-paths.adoc | 7 +- .../operators/operators-detail.adoc | 28 +- .../ROOT/pages/subqueries/call-subquery.adoc | 655 +++++++++++++----- .../subqueries-in-transactions.adoc | 123 +--- 11 files changed, 623 insertions(+), 276 deletions(-) diff --git a/modules/ROOT/images/call_subquery_graph.svg b/modules/ROOT/images/call_subquery_graph.svg index 10e7f2ae6..932cf79da 100644 --- a/modules/ROOT/images/call_subquery_graph.svg +++ b/modules/ROOT/images/call_subquery_graph.svg @@ -1,9 +1,9 @@ - - + + - - + + - + diff --git a/modules/ROOT/pages/appendix/gql-conformance/index.adoc b/modules/ROOT/pages/appendix/gql-conformance/index.adoc index 2bc52908d..9448c41c4 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/index.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/index.adoc @@ -1,8 +1,8 @@ :description: Overview of Cypher's conformance to GQL. = GQL conformance -*Last updated*: 5 July 2024 + -*Neo4j version*: 5.21 +*Last updated*: 8 August 2024 + +*Neo4j version*: 5.23 GQL is the new link:https://www.iso.org/home.html[ISO] International Standard query language for graph databases. diff --git a/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc b/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc index 42cd41056..4d4ee103d 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc @@ -81,7 +81,7 @@ This is not available in Cypher. | | xref:subqueries/call-subquery.adoc[`CALL` subqueries]. | GQL either imports variables implicitly, or explicitly using a variable scope clause. -In Cypher, `CALL` subqueries require an explicit importing `WITH` clause. +In Cypher, it is currently not possible to implicitly import variables. | 15.3 | diff --git a/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc b/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc index 47ba67e7f..c8c76ab6c 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc @@ -129,6 +129,14 @@ In Cypher, `trim()` removes any whitespace character. | | +| GP01 +| xref:subqueries/call-subquery.adoc[Inline procedure] +| + +| GP03 +| xref:subqueries/call-subquery.adoc#variable-scope-clause[Inline procedure with explicit nested variable scope] +| + | GQ01 | `USE` graph clause | xref:clauses/use.adoc[`USE`] diff --git a/modules/ROOT/pages/clauses/load-csv.adoc b/modules/ROOT/pages/clauses/load-csv.adoc index ea1998c5e..a67c11b2a 100644 --- a/modules/ROOT/pages/clauses/load-csv.adoc +++ b/modules/ROOT/pages/clauses/load-csv.adoc @@ -599,12 +599,15 @@ person_tmdbId,bio,born,bornIn,died,person_imdbId,name,person_poster,person_url ... ---- +[NOTE] +The below query uses a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] (introduced in Neo4j 5.23) to import variables into the `CALL` subquery. +If you are using an older version of Neo4j, use an xref:subqueries/call-subquery.adoc#importing-with[importing `WITH` clause] instead. + .Query [source, cypher] ---- LOAD CSV WITH HEADERS FROM 'https://data.neo4j.com/importing-cypher/persons.csv' AS row -CALL { - WITH row +CALL (row) { MERGE (p:Person {tmdbId: row.person_tmdbId}) SET p.name = row.name, p.born = row.born } IN TRANSACTIONS OF 200 ROWS diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index 62109c01f..83437bedb 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -19,8 +19,33 @@ Replacement syntax for deprecated and removed features are also indicated. [[cypher-deprecations-additions-removals-5.23]] == Neo4j 5.23 +=== Deprecated features + +[cols="2", options="header"] +|=== +| Feature +| Details + +a| +label:functionality[] +label:deprecated[] +[source, cypher, role="noheader"] +---- +UNWIND [0, 1, 2] AS x +CALL { + WITH x + RETURN x * 10 AS y +} +RETURN x, y +---- + +| Using the xref:subqueries/call-subquery.adoc#importing-with[`WITH` clause to import variables] to `CALL` subqueries is deprecated, and replaced with a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause]. +It is also deprecated to use naked subqueries without a variable scope clause. +|=== + === Updated features + [cols="2", options="header"] |=== | Feature @@ -39,6 +64,29 @@ Introduced new GQL conformant aliases to duration types: `TIMESTAMP WITHOUT TIME See xref::values-and-types/property-structural-constructed.adoc#types-synonyms[types and their synonyms] for more. |=== +=== New features + +[cols="2", options="header"] +|=== +| Feature +| Details + +a| +label:functionality[] +label:new[] +[source, cypher, role="noheader"] +---- +UNWIND [0, 1, 2] AS x +CALL (x) { + RETURN x * 10 AS y +} +RETURN x, y +---- + +| Introduced a new xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] to import variables in `CALL` subqueries. + +|=== + [[cypher-deprecations-additions-removals-5.21]] == Neo4j 5.21 diff --git a/modules/ROOT/pages/genai-integrations.adoc b/modules/ROOT/pages/genai-integrations.adoc index eba7d181b..0ffed1b6d 100644 --- a/modules/ROOT/pages/genai-integrations.adoc +++ b/modules/ROOT/pages/genai-integrations.adoc @@ -180,9 +180,8 @@ WITH collect(m) AS moviesList // <1> count(*) AS total, 100 AS batchSize // <2> UNWIND range(0, total, batchSize) AS batchStart // <3> -CALL { // <4> - WITH moviesList, batchStart, batchSize - WITH moviesList, batchStart, [movie IN moviesList[batchStart .. batchStart + batchSize] | movie.title || ': ' || movie.plot] AS resources // <5> +CALL (moviesList, batchStart, batchSize) { // <4> + WITH [movie IN moviesList[batchStart .. batchStart + batchSize] | movie.title || ': ' || movie.plot] AS resources // <5> CALL genai.vector.encodeBatch(batch, 'OpenAI', { token: $token }) YIELD index, vector CALL db.create.setNodeVectorProperty(moviesList[batchStart + index], 'embedding', vector) // <6> } IN TRANSACTIONS OF 1 ROW <7> @@ -194,6 +193,8 @@ Because vector embeddings can be very large, a larger batch size may require sig Too large a batch size may also exceed the provider's threshold. <3> Process `Movie` nodes in increments of `batchSize`. <4> A xref:subqueries/subqueries-in-transactions.adoc[`CALL` subquery] executes a separate transaction for each batch. +Note that this `CALL` subquery uses a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] (introduced in Neo4j 5.23) to import variables. +If you are using an older version of Neo4j, use an xref:subqueries/call-subquery.adoc#importing-with[importing `WITH` clause] instead. <5> `resources` is a list of strings, each being the concatenation of `title` and `plot` of one movie. <6> The procedure sets `vector` as value for the property named `embedding` for the node at position `batchStart + index` in the `moviesList`. <7> Set to `1` the amount of batches to be processed at once. diff --git a/modules/ROOT/pages/patterns/shortest-paths.adoc b/modules/ROOT/pages/patterns/shortest-paths.adoc index 2e9779c75..01e61f3ba 100644 --- a/modules/ROOT/pages/patterns/shortest-paths.adoc +++ b/modules/ROOT/pages/patterns/shortest-paths.adoc @@ -552,6 +552,10 @@ To have the planner choose the `StatefulShortestPath(Into)` instead, rewrite the For example, in the below query, using a `CALL` subquery ensures that the planner binds `a` and `b` to exactly one `Station` node respectively for each executed row, and this forces it to use `StatefulShortestPath(Into)` for each invocation of the `CALL` subquery, since a precondition of using this operator is that both boundary nodes match exactly one node each. +[NOTE] +The below query uses a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] (introduced in Neo4j 5.23) to import variables into the `CALL` subquery. +If you are using an older version of Neo4j, use an xref:subqueries/call-subquery.adoc#importing-with[importing `WITH` clause] instead. + .Query rewritten to use `StatefulShortestPath(Into)` [source,cypher] ---- @@ -559,8 +563,7 @@ PROFILE MATCH (a:Station {name: "Worcestershire Parkway"}), (b:Station) -CALL { - WITH a, b +CALL (a, b) { MATCH p = SHORTEST 1 (a)(()-[]-()-[]-()){1,}(b) RETURN p diff --git a/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc b/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc index 38759c6f5..d6c0f97d8 100644 --- a/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc +++ b/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc @@ -2811,13 +2811,16 @@ Total database accesses: 166, total allocated memory: 976 .TransactionApply ====== +[NOTE] +The below query uses a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] (introduced in Neo4j 5.23) to import variables into the `CALL` subquery. +If you are using an older version of Neo4j, use an xref:subqueries/call-subquery.adoc#importing-with[importing `WITH` clause] instead. + .Query [source, cypher] ---- PROFILE LOAD CSV FROM 'https://neo4j.com/docs/cypher-refcard/3.3/csv/artists.csv' AS line -CALL { - WITH line +CALL (line) { CREATE (a: Artist {name: line[0]}) RETURN a } IN TRANSACTIONS OF 100 ROWS @@ -3512,13 +3515,16 @@ This restricts the xref:planning-and-tuning/runtimes/index.adoc[Cypher runtime] .ArgumentTracker ====== +[NOTE] +The below query uses a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] (introduced in Neo4j 5.23) to import variables into the `CALL` subquery. +If you are using an older version of Neo4j, use an xref:subqueries/call-subquery.adoc#importing-with[importing `WITH` clause] instead. + .Query [source, cypher] ---- PROFILE MATCH (s:Person {name: 'me'}) -CALL { - WITH s +CALL (s) { SET s.seen = coalesce(s.seen + 1,1) RETURN s.seen AS result } @@ -4787,13 +4793,16 @@ Total database accesses: 9, total allocated memory: 64 .TransactionForeach ====== +[NOTE] +The below query uses a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] (introduced in Neo4j 5.23) to import variables into the `CALL` subquery. +If you are using an older version of Neo4j, use an xref:subqueries/call-subquery.adoc#importing-with[importing `WITH` clause] instead. + .Query [source, cypher] ---- PROFILE LOAD CSV FROM 'https://neo4j.com/docs/cypher-refcard/3.3/csv/artists.csv' AS line -CALL { - WITH line +CALL (line) { CREATE (a: Artist {name: line[0]}) } IN TRANSACTIONS OF 100 ROWS ---- @@ -4839,13 +4848,16 @@ Batch size 128 .SubqueryForeach ====== +[NOTE] +The below query uses a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] (introduced in Neo4j 5.23) to import variables into the `CALL` subquery. +If you are using an older version of Neo4j, use an xref:subqueries/call-subquery.adoc#importing-with[importing `WITH` clause] instead. + .Query [source, cypher] ---- PROFILE LOAD CSV FROM 'https://neo4j.com/docs/cypher-refcard/3.3/csv/artists.csv' AS line -CALL { - WITH line +CALL (line) { CREATE (a: Artist {name: line[0]}) } ---- diff --git a/modules/ROOT/pages/subqueries/call-subquery.adoc b/modules/ROOT/pages/subqueries/call-subquery.adoc index 636d47eea..84624ee19 100644 --- a/modules/ROOT/pages/subqueries/call-subquery.adoc +++ b/modules/ROOT/pages/subqueries/call-subquery.adoc @@ -1,19 +1,17 @@ = CALL subqueries -:description: This page describes how to use the CALL subquery with Cypher. +:description: This page describes how to use Cypher's `CALL` subquery. -The `CALL` clause can be used to invoke a subquery. -Unlike other subqueries in Cypher, it can be used to perform changes to the database (e.g. xref:clauses/create.adoc[] new nodes), and it requires an importing xref:clauses/with.adoc[] clause. +The `CALL` clause can be used to invoke subqueries that execute operations within a defined scope, thereby optimizing data handling and query efficiency. +Unlike other subqueries in Cypher, `CALL` subqueries can be used to perform changes to the database (e.g. xref:clauses/create.adoc[] new nodes). [NOTE] -==== The `CALL` clause is also used for calling procedures. -For descriptions of the `CALL` clause in this context, refer to xref::clauses/call.adoc[`CALL` procedure]. -==== +For descriptions of the `CALL` clause in this context, refer to the xref::clauses/call.adoc[`CALL` procedure]. [[call-example-graph]] == Example graph -The following graph is used for the examples below: +A graph with the following schema is used for the examples below: image::call_subquery_graph.svg[] @@ -21,33 +19,45 @@ To recreate the graph, run the following query in an empty Neo4j database: [source, cypher, role=test-setup] ---- -CREATE - (a:Person:Child {name: 'Alice', age: 20}), - (b:Person {name: 'Bob', age: 27}), - (c:Person:Parent {name: 'Charlie', age: 65}), - (d:Person {name: 'Dora', age: 30}) - CREATE (a)-[:FRIEND_OF]->(b) - CREATE (a)-[:CHILD_OF]->(c) - CREATE (a)-[:OWES {dollars: 20}]->(c) - CREATE (a)-[:OWES {dollars: 25}]->(b) - CREATE (b)-[:OWES {dollars: 35}]->(d) - CREATE (d)-[:OWES {dollars: 15}]->(b) - CREATE (d)-[:OWES {dollars: 30}]->(b) -CREATE (:Counter {count: 0}) +CREATE (teamA:Team {name: 'Team A'}), + (teamB:Team {name: 'Team B'}), + (teamC:Team {name: 'Team C'}), + (playerA:Player {name: 'Player A', age: 21}), + (playerB:Player {name: 'Player B', age: 23}), + (playerC:Player {name: 'Player C', age: 19}), + (playerD:Player {name: 'Player D', age: 30}), + (playerE:Player {name: 'Player E', age: 25}), + (playerF:Player {name: 'Player F', age: 35}), + (playerA)-[:PLAYS_FOR]->(teamA), + (playerB)-[:PLAYS_FOR]->(teamA), + (playerC)-[:PLAYS_FOR]->(teamA), + (playerD)-[:PLAYS_FOR]->(teamB), + (playerE)-[:PLAYS_FOR]->(teamC), + (playerF)-[:PLAYS_FOR]->(teamC), + (playerA)-[:FRIEND_OF]->(playerB), + (playerA)-[:FRIEND_OF]->(playerC), + (playerB)-[:FRIEND_OF]->(playerF), + (playerC)-[:FRIEND_OF]->(playerD), + (teamA)-[:OWES {dollars: 1500}]->(teamB), + (teamA)-[:OWES {dollars: 3000}]->(teamB), + (teamB)-[:OWES {dollars: 1700}]->(teamC), + (teamC)-[:OWES {dollars: 5000}]->(teamB) ---- -[[call-semantics]] -== Semantics +== Semantics and performance A `CALL` subquery is executed once for each incoming row. +The variables returned in a subquery are available to the outer scope of the enclosing query. -In the below example, the `CALL` subquery executes three times, one for each row that the `UNWIND` clause outputs. +.Basic example +==== +In this example, the `CALL` subquery executes three times, one for each row that the xref:clauses/unwind.adoc[`UNWIND`] clause outputs. .Query [source, cypher] ---- UNWIND [0, 1, 2] AS x -CALL { +CALL () { RETURN 'hello' AS innerReturn } RETURN innerReturn @@ -57,84 +67,360 @@ RETURN innerReturn [role="queryresult",options="header,footer",cols="m"] |=== | innerReturn + | 'hello' | 'hello' | 'hello' -d|Rows:3 + +d|Rows: 3 |=== +==== Each execution of a `CALL` subquery can observe changes from previous executions. +This allows for the accumulation of results and the progressive transformation of data within a single Cypher query. -.Query +.Incremental updates +==== +In this example, each iteration of the `CALL` subquery adds 1 to the `age` of `Player A` and the returned `newAge` reflects the `age` after each increment. + +.Incrementally update the age property of a Player [source, cypher] ---- -UNWIND [0, 1, 2] AS x -CALL { - MATCH (n:Counter) - SET n.count = n.count + 1 - RETURN n.count AS innerCount +UNWIND [1, 2, 3] AS x +CALL () { + MATCH (p:Player {name: 'Player A'}) + SET p.age = p.age + 1 + RETURN p.age AS newAge } -WITH innerCount -MATCH (n:Counter) -RETURN - innerCount, - n.count AS totalCount +WITH x, newAge +MATCH (p:Player {name: 'Player A'}) +RETURN x AS iteration, newAge, p.age AS totalAge ---- .Result -[role="queryresult",options="header,footer",cols=""2*(t) + RETURN collect(p) as players +} +RETURN t AS team, players +---- -[NOTE] +.Result +[source, role="queryresult",options="header,footer",cols="m,2m"] +|=== +| team +| players + +| (:Team {name: "Team A"}) +| [(:Player {name: "Player C", age: 19}), (:Player {name: "Player B", age: 23}), (:Player {name: "Player A", age: 24})] + +| (:Team {name: "Team B"}) +| [(:Player {name: "Player D", age: 30})] + +| (:Team {name: "Team C"}) +| [(:Player {name: "Player F", age: 35}), (:Player {name: "Player E", age: 25})] + +2+d|Rows: 3 +|=== + +The `CALL` subquery ensures that each `Team` is processed separately (one row per `Team` node), rather than having to hold every `Team` and `Player` node in heap memory simultaneously before collecting them into lists. +Using a `CALL` subquery can therefore reduce the amount of heap memory required for an operation. ==== -References to a variable in the outer scope that were not imported will introduce a new variable. + +[[import-variables]] +== Importing variables + +Variables from the outer scope must be explicitly imported into the inner scope of the `CALL` subquery, either by using a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] or an xref:subqueries/call-subquery.adoc#importing-with[importing `WITH` clause] (deprecated). +As the subquery is evaluated for each incoming input row, the imported variables are assigned the corresponding values from that row. + +[role=label--new-5.23] +[[variable-scope-clause]] +=== The variable scope clause + +Variables can be imported into a `CALL` subquery using a scope clause: `CALL ()`. +Using the scope clause disables the deprecated xref:subqueries/call-subquery.adoc#importing-with[importing `WITH`] clause. + +A scope clause can be used to import all, specific, or none of the variables from the outer scope. + +.Import specific variables from the outer scope ==== -As the subquery is evaluated for each incoming input row, the imported variables get bound to the corresponding values from the input row in each evaluation. +This example only imports the `p` variable from the outer scope and uses it to create a new, randomly generated, `rating` property for each `Player` node. +It then returns the `Player` node with the highest `rating`. -.Query +.Import one variable from the outer scope +[source, cypher, role=test-result-skip] +---- +MATCH (p:Player), (t:Team) +CALL (p) { + WITH rand() AS random + SET p.rating = random + RETURN p.name AS playerName, p.rating AS rating +} +RETURN playerName, rating, t AS team +ORDER BY rating +LIMIT 1 +---- + +.Result +[source, role="queryresult",options="header,footer",cols="3*m"] +|=== +| playerName +| rating +| team + +| "Player C" +| 0.9307432039870395 +| "Team A" + +3+d|Rows: 1 + +|=== + +To import additional variables, include them within the parentheses after `CALL`, separated by commas. +For example, to import both variables from the `MATCH` clause in the above query, modify the scope clause accordingly: `CALL (p, t)`. +==== + +.Import all variables +==== +To import all variables from the outer scope, use `CALL (*)`. +This example imports both the `p` and `t` variables and sets a new `lastUpdated` property on both. + +.Import all variables from the outer scope +[source, cypher, role=test-result-skip] +---- +MATCH (p:Player), (t:Team) +CALL (*) { + SET p.lastUpdated = timestamp() + SET t.lastUpdated = timestamp() +} +RETURN p.name AS playerName, + p.lastUpdated AS playerUpdated, + t.name AS teamName, + t.lastUpdated AS teamUpdated +LIMIT 1 +---- + +.Result +[source, role="queryresult",options="header,footer",cols="4*m"] +|=== + +| playerName +| playerUpdated +| teamName +| teamUpdated + +| "Player A" +| 1719304206653 +| "Team A" +| 1719304206653 + +4+d|Rows: 1 +|=== +==== + +.Import no variables +==== +To import no variables from the outer scope, use `CALL ()`. + +.Import no variables from the outer scope [source, cypher] ---- -UNWIND [0, 1, 2] AS x -CALL { - WITH x - RETURN x * 10 AS y +MATCH (t:Team) +CALL () { + MATCH (p:Player) + RETURN count(p) AS totalPlayers } -RETURN x, y +RETURN count(t) AS totalTeams, totalPlayers ---- .Result -[role="queryresult",options="header,footer",cols="2*(teams) + RETURN collect(p) as players +} +RETURN t AS teams, players +---- +* The scope clause’s variables cannot be re-declared in the subquery. + +.Not allowed +[source,cypher,role=test-fail] +---- +MATCH (t:Team) +CALL (t) { + WITH 'New team' AS t + MATCH (p:Player)-[:PLAYS_FOR]->(t) + RETURN collect(p) as players +} +RETURN t AS team, players +---- + +* The subquery cannot return a variable name which already exists in the outer scope. +To return imported variables they must be renamed. + +.Not allowed +[source,cypher,role=test-fail] +---- +MATCH (t:Team) +CALL (t) { + RETURN t +} +RETURN t +---- + +[role=label--deprecated] +[[importing-with]] +=== Importing `WITH` clause + +Variables can also be imported into a `CALL` subquery using an importing `WITH` clause. +Note that this syntax is not xref:appendix/gql-conformance/index.adoc[GQL conformant]. + +.Variables imported by `WITH` clause +[source, cypher] +---- +MATCH (t:Team) +CALL { + WITH t + MATCH (p:Player)-[:PLAYS_FOR]->(t) + RETURN collect(p) as players +} +RETURN t AS teams, players +---- + +.Click to read more about importing variables using the `WITH` clause +[%collapsible] +==== + +* Just as when using a variable scope clause, a subquery using an importing `WITH` clause cannot return a variable name which already exists in the outer scope. +To return imported variables they must be renamed. + +* The importing `WITH` clause must the first clause of a subquery (or the second clause, if directly following a `USE` clause). +* It is not possible to follow an importing `WITH` clause with any of the following clauses: `DISTINCT`, `ORDER BY`, `WHERE`, `SKIP`, and `LIMIT`. + +Attempting any of the above, will throw an error. +For example, the following query using a `WHERE` clause after an importing `WITH` clause will throw an error: + +.Not Allowed +[source, cypher, role=test-fail] +---- +UNWIND [[1,2],[1,2,3,4],[1,2,3,4,5]] AS l +CALL { + WITH l + WHERE size(l) > 2 + RETURN l AS largeLists +} +RETURN largeLists +---- + +.Error message +[source, error] +---- +Importing WITH should consist only of simple references to outside variables. +WHERE is not allowed. +---- + +A solution to this restriction, necessary for any filtering or ordering of an importing `WITH` clause, is to declare a second `WITH` clause after the importing `WITH` clause. +This second `WITH` clause will act as a regular `WITH` clause. +For example, the following query will not throw an error: + +.Allowed +[source, cypher] +---- +UNWIND [[1,2],[1,2,3,4],[1,2,3,4,5]] AS l +CALL { + WITH l + WITH l + WHERE size(l) > 2 + RETURN l AS largeLists +} +RETURN largeLists +---- + +.Result +[role="queryresult",options="header,footer",cols="1*(nextPerson) - RETURN current AS from, nextPerson AS to + SET nextPlayer:ListHead + CREATE(current)-[:IS_YOUNGER_THAN]->(nextPlayer) + RETURN current AS from, nextPlayer AS to } RETURN from.name AS name, @@ -171,81 +460,108 @@ RETURN ---- .Result -[role="queryresult",options="header,footer",cols="4*(other:Person) - RETURN o.dollars * -1 AS moneyOwed -UNION ALL - WITH p - OPTIONAL MATCH (other:Person)-[o:OWES]->(p) - RETURN o.dollars AS moneyOwed +MATCH (t:Team) +CALL (t) { + OPTIONAL MATCH (t)-[o:OWES]->(other:Team) + RETURN o.dollars * -1 AS moneyOwed + UNION ALL + OPTIONAL MATCH (other)-[o:OWES]->(t) + RETURN o.dollars AS moneyOwed } -RETURN p.name, sum(moneyOwed) AS amountOwing +RETURN t.name AS team, sum(moneyOwed) AS amountOwed +ORDER BY amountOwed DESC ---- .Result [role="queryresult",options="header,footer",cols="2*(p2:Player) + RETURN p2.name AS friend } -RETURN p.name, friend +RETURN p.name AS player, friend ---- .Result [role="queryresult",options="header,footer",cols="2*(c) - RETURN sum(o.dollars) AS owedAmount, c.name AS owedName +MATCH (t:Team) +CALL (t) { + MATCH (t)-[o:OWES]->(t2:Team) + RETURN sum(o.dollars) AS owedAmount, t2.name AS owedTeam } -RETURN p.name, owedAmount, owedName +RETURN t.name AS owingTeam, owedAmount, owedTeam ---- .Result [role="queryresult",options="header,footer",cols="3* 100 -CALL { - WITH n +CALL (n) { DETACH DELETE n } IN TRANSACTIONS ---- @@ -158,8 +158,7 @@ This example loads a CSV file with one transaction for every `2` input rows: [source, cypher] ---- LOAD CSV FROM 'file:///friends.csv' AS line -CALL { - WITH line +CALL (line) { CREATE (:Person {name: line[1], age: toInteger(line[2])}) } IN TRANSACTIONS OF 2 ROWS ---- @@ -191,8 +190,7 @@ For example: [source, cypher] ---- MATCH (n) -CALL { - WITH n +CALL (n) { DETACH DELETE n } IN TRANSACTIONS OF 2 ROWS ---- @@ -243,9 +241,8 @@ The following examples show how you can use `CALL { ... } IN TRANSACTIONS` on a ---- UNWIND graph.names() AS graphName LOAD CSV FROM 'file:///friends.csv' AS line -CALL { +CALL (*) { USE graph.byName( graphName ) - WITH line CREATE (:Person {name: line[1], age: toInteger(line[2])}) } IN TRANSACTIONS ---- @@ -306,7 +303,7 @@ While the declared batch size is 3, only the first 2 rows act on `composite.remo WITH ['composite.remoteGraph1', 'composite.remoteGraph2'] AS graphs UNWIND [0, 0, 1, 1, 1, 1, 0, 0] AS i WITH graphs[i] AS g -CALL { +CALL (g) { USE graph.byName( g ) CREATE () } IN TRANSACTIONS OF 3 ROWS @@ -339,8 +336,7 @@ due to division by zero. [source, cypher, role=test-fail] ---- UNWIND [4, 2, 1, 0] AS i -CALL { - WITH i +CALL (i) { CREATE (:Person {num: 100/i}) } IN TRANSACTIONS OF 2 ROWS RETURN i @@ -376,8 +372,7 @@ In the following example, `ON ERROR CONTINUE` is used after a failed inner trans [source, cypher] ---- UNWIND [1, 0, 2, 4] AS i -CALL { - WITH i +CALL (i) { CREATE (n:Person {num: 100/i}) // Note, fails when i = 0 RETURN n } IN TRANSACTIONS @@ -403,8 +398,7 @@ Note the difference in results when batching in transactions of 2 rows: [source, cypher, indent=0] ---- UNWIND [1, 0, 2, 4] AS i -CALL { - WITH i +CALL (i) { CREATE (n:Person {num: 100/i}) // Note, fails when i = 0 RETURN n } IN TRANSACTIONS @@ -435,8 +429,7 @@ In the following example, `ON ERROR BREAK` is used after a failed inner transact [source, cypher, indent=0] ---- UNWIND [1, 0, 2, 4] AS i -CALL { - WITH i +CALL (i) { CREATE (n:Person {num: 100/i}) // Note, fails when i = 0 RETURN n } IN TRANSACTIONS @@ -462,8 +455,7 @@ Note the difference in results when batching in transactions of 2 rows: [source, cypher, indent=0] ---- UNWIND [1, 0, 2, 4] AS i -CALL { - WITH i +CALL (i) { CREATE (n:Person {num: 100/i}) // Note, fails when i = 0 RETURN n } IN TRANSACTIONS @@ -489,8 +481,7 @@ In the following example, `ON ERROR FAIL` is used after the failed inner transac [source, cypher, indent=0, role=test-fail] ---- UNWIND [1, 0, 2, 4] AS i -CALL { - WITH i +CALL (i) { CREATE (n:Person {num: 100/i}) // Note, fails when i = 0 RETURN n } IN TRANSACTIONS @@ -529,8 +520,7 @@ Example of reporting status with `ON ERROR CONTINUE`: [source, cypher, indent=0, role=test-result-skip] ---- UNWIND [1, 0, 2, 4] AS i -CALL { - WITH i +CALL (i) { CREATE (n:Person {num: 100/i}) // Note, fails when i = 0 RETURN n } IN TRANSACTIONS @@ -557,8 +547,7 @@ Example of reporting status with `ON ERROR BREAK`: [source, cypher, indent=0] ---- UNWIND [1, 0, 2, 4] AS i -CALL { - WITH i +CALL (i) { CREATE (n:Person {num: 100/i}) // Note, fails when i = 0 RETURN n } IN TRANSACTIONS @@ -585,8 +574,7 @@ Reporting status with `ON ERROR FAIL` is disallowed: [source, cypher, role=test-fail] ---- UNWIND [1, 0, 2, 4] AS i -CALL { - WITH i +CALL (i) { CREATE (n:Person {num: 100/i}) // Note, fails when i = 0 RETURN n } IN TRANSACTIONS @@ -625,8 +613,7 @@ This example creates `Person` nodes from a unique `tmdbId` value assigned to eac [source, cypher] ---- LOAD CSV WITH HEADERS FROM 'https://data.neo4j.com/importing-cypher/persons.csv' AS row -CALL { - WITH row +CALL (row) { CREATE (p:Person {tmdbId: row.person_tmdbId}) SET p.name = row.name, p.born = row.born } IN 3 CONCURRENT TRANSACTIONS OF 10 ROWS @@ -684,8 +671,7 @@ Note that there are only three different years in the CSV file, meaning hat only [source, cypher, role=test-fail] ---- LOAD CSV WITH HEADERS FROM 'https://data.neo4j.com/importing-cypher/movies.csv' AS row -CALL { - WITH row +CALL (row) { MERGE (m:Movie {movieId: row.movieId}) MERGE (y:Year {year: row.year}) MERGE (m)-[r:RELEASED_IN]->(y) @@ -709,8 +695,7 @@ It returns the `transactionID`, `commitStatus` and `errorMessage` of the failed [source, cypher] ---- LOAD CSV WITH HEADERS FROM 'https://data.neo4j.com/importing-cypher/movies.csv' AS row -CALL { - WITH row +CALL (row) { MERGE (m:Movie {movieId: row.movieId}) MERGE (y:Year {year: row.year}) MERGE (m)-[r:RELEASED_IN]->(y) @@ -724,7 +709,7 @@ RETURN status.transactionId AS transaction, status.committed AS commitStatus, st [source, "queryresult"] ---- +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| transaction | commitStatus | errorMessage | +| transaction | commitStatus | errorMessage | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | "neo4j-transaction-169" | FALSE | "ForsetiClient[transactionId=169, clientId=11] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=168, clientId=9]} on NODE_RELATIONSHIP_GROUP_DELETE(46) because holders of that lock are waiting for ForsetiClient[transactionId=169, clientId=11]. | | | \ Wait list:ExclusiveLock[ | @@ -768,16 +753,14 @@ While failed transactions may be more efficiently retried using a link:{neo4j-do [source, cypher] ---- LOAD CSV WITH HEADERS FROM 'https://data.neo4j.com/importing-cypher/movies.csv' AS row -CALL { - WITH row +CALL (row) { MERGE (m:Movie {movieId: row.movieId}) MERGE (y:Year {year: row.year}) MERGE (m)-[r:RELEASED_IN]->(y) } IN 2 CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR CONTINUE REPORT STATUS as status WITH * WHERE status.committed = false -CALL { - WITH row +CALL (row) { MERGE (m:Movie {movieId: row.movieId}) MERGE (y:Year {year: row.year}) MERGE (m)-[r:RELEASED_IN]->(y) @@ -795,59 +778,3 @@ These are the restrictions on queries that use `CALL { ... } IN TRANSACTIONS`: * A `CALL { ... } IN TRANSACTIONS` in a `UNION` is not supported. * A `CALL { ... } IN TRANSACTIONS` after a write clause is not supported, unless that write clause is inside a `CALL { ... } IN TRANSACTIONS`. -Additionally, there are some restrictions that apply when using an importing `WITH` clause in a `CALL` subquery: - -* Only variables imported with the importing `WITH` clause can be used. -* No expressions or aliasing are allowed within the importing `WITH` clause. -* It is not possible to follow an importing `WITH` clause with any of the following clauses: `DISTINCT`, `ORDER BY`, `WHERE`, `SKIP`, and `LIMIT`. - -Attempting any of the above, will throw an error. -For example, the following query using a `WHERE` clause after an importing `WITH` clause will throw an error: - -.Query -[source, cypher, role=test-fail] ----- -UNWIND [[1,2],[1,2,3,4],[1,2,3,4,5]] AS l -CALL { - WITH l - WHERE size(l) > 2 - RETURN l AS largeLists -} -RETURN largeLists ----- - -.Error message -[source, error] ----- -Importing WITH should consist only of simple references to outside variables. -WHERE is not allowed. ----- - -A solution to this restriction, necessary for any filtering or ordering of an importing `WITH` clause, is to declare a second `WITH` clause after the importing `WITH` clause. -This second `WITH` clause will act as a regular `WITH` clause. -For example, the following query will not throw an error: - -.Query -[source, cypher] ----- -UNWIND [[1,2],[1,2,3,4],[1,2,3,4,5]] AS l -CALL { - WITH l - WITH size(l) AS size, l AS l - WHERE size > 2 - RETURN l AS largeLists -} -RETURN largeLists ----- - -.Result -[role="queryresult",options="header,footer",cols="1* Date: Thu, 8 Aug 2024 16:21:22 +0200 Subject: [PATCH 06/64] Fix typos on parsing page (#1014) --- modules/ROOT/pages/syntax/parsing.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/ROOT/pages/syntax/parsing.adoc b/modules/ROOT/pages/syntax/parsing.adoc index 0a64ed215..54db83bde 100644 --- a/modules/ROOT/pages/syntax/parsing.adoc +++ b/modules/ROOT/pages/syntax/parsing.adoc @@ -15,7 +15,7 @@ Additional documentation on escaping rules for `STRING` literals, names and regu * xref::queries/expressions.adoc#expressions-string-literals[String literal escape sequences] * xref::syntax/naming.adoc#symbolic-names-escaping-rules[Using special characters in names] -* xref::clauses/where.adoc#escaping-in-regular-expressions[Regular epxressions] +* xref::clauses/where.adoc#escaping-in-regular-expressions[Regular expressions] The following example escapes the unicode character `A` (`\u0041`) in the keyword `MATCH`: @@ -44,9 +44,9 @@ The following unicode characters are considered as whitespace: [options="header", cols="1,2"] |=== | Description | List of included Unicode characters -| Unicode general gategory Zp | `\u2029` -| Unicode general gategory Zs | `\u0020` (space), `\u1680`, `\u2000-200A`, `\u202F`, `\u205F`, `\u3000` -| Unicode general gategory class Zl | `\u2028` +| Unicode general category Zp | `\u2029` +| Unicode general category Zs | `\u0020` (space), `\u1680`, `\u2000-200A`, `\u202F`, `\u205F`, `\u3000` +| Unicode general category class Zl | `\u2028` | Horizontal tabulation | `\t`, `\u0009` | Line feed | `\n`, `\u000A` | Vertical tabulation | `\u000B` From 2014d2a04257253f6a398e809a2e2a7613dad205 Mon Sep 17 00:00:00 2001 From: Gem Lamont <106068376+gem-neo4j@users.noreply.github.com> Date: Fri, 9 Aug 2024 09:22:17 +0200 Subject: [PATCH 07/64] Add further considerations for CASE expressions (#1013) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- modules/ROOT/pages/queries/case.adoc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/modules/ROOT/pages/queries/case.adoc b/modules/ROOT/pages/queries/case.adoc index 04ac4f195..1dae13b99 100644 --- a/modules/ROOT/pages/queries/case.adoc +++ b/modules/ROOT/pages/queries/case.adoc @@ -323,3 +323,29 @@ RETURN n.name, n.colorCode |=== For more information about using the `SET` clause, see xref::clauses/set.adoc[SET]. + +== Further considerations + +`CASE` result branches are statically checked prior to execution. +This means that if a branch is not semantically correct, it will still throw an exception, even if that branch may never be executed during runtime. + +In the following example, `date` is statically known to be a `STRING` value, and therefore would fail if treated as a `DATE` value. + +.Not allowed +[source, cypher, role=test-fail] +---- +WITH "2024-08-05" AS date, "string" AS type +RETURN CASE type + WHEN "string" THEN datetime(date) + WHEN "date" THEN datetime({year: date.year, month: date.month, day: date.day}) + ELSE datetime(date) +END AS dateTime +---- + +.Error message +[source, error] +---- +Type mismatch: expected Map, Node, Relationship, Point, Duration, Date, Time, LocalTime, LocalDateTime or DateTime but was String (line 4, column 38 (offset: 136)) +" WHEN 'date' THEN datetime({year: date.year, month: date.month, day: date.day})" + ^ +---- \ No newline at end of file From 20b83d771468bddc504690a94f880464d333968c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Fri, 9 Aug 2024 13:41:00 +0200 Subject: [PATCH 08/64] Remove link to Cartesian CRSs (#1016) --- modules/ROOT/pages/values-and-types/spatial.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/values-and-types/spatial.adoc b/modules/ROOT/pages/values-and-types/spatial.adoc index a7daf8684..dce319fb1 100644 --- a/modules/ROOT/pages/values-and-types/spatial.adoc +++ b/modules/ROOT/pages/values-and-types/spatial.adoc @@ -95,10 +95,10 @@ RETURN toInteger(point.distance(p1, p2)/1000) AS km Two Cartesian Coordinate Reference Systems (CRS) are supported, modeling points in euclidean space: -* link:https://spatialreference.org/ref/sr-org/7203/[Cartesian 2D] +* *Cartesian 2D* ** A 2D point in the _Cartesian_ CRS is specified with a map containing `x` and `y` coordinate values ** Specifying this CRS can be done using either the name 'cartesian' or the SRID 7203 as described in xref::functions/spatial.adoc#functions-point-cartesian-2d[point() - Cartesian 2D] -* link:https://spatialreference.org/ref/sr-org/9157/[Cartesian 3D] +* *Cartesian 3D* ** A 3D point in the _Cartesian_ CRS is specified with a map containing `x`, `y` and `z` coordinate values ** Specifying this CRS can be done using either the name 'cartesian-3d' or the SRID 9157 as described in xref::functions/spatial.adoc#functions-point-cartesian-3d[point() - Cartesian 3D)] From 21d63cc9641ecd8b361cdac32870ae5f0588e7a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Fri, 9 Aug 2024 13:53:55 +0200 Subject: [PATCH 09/64] Fix typo in Patterns reference (#1017) --- modules/ROOT/pages/patterns/reference.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/pages/patterns/reference.adoc b/modules/ROOT/pages/patterns/reference.adoc index f145e88bb..d9da89346 100644 --- a/modules/ROOT/pages/patterns/reference.adoc +++ b/modules/ROOT/pages/patterns/reference.adoc @@ -779,7 +779,7 @@ Matches one or more relationships with type `R` and of any direction, and any no ()-[:R]-+() ---- -Matches paths consisting of two inbound subpaths, one with relationships of type `A` and one with relationships of type `B`, meeting at a node with label `A`: +Matches paths consisting of two inbound subpaths, one with relationships of type `R` and one with relationships of type `S`, meeting at a node with label `A`: [source, role=noheader] ---- ()-[:R]->+(:A)<-[:S]-+() From 79cbee9c0f908781464d530e681f687382ba740a Mon Sep 17 00:00:00 2001 From: Phil Wright <95368282+phil198@users.noreply.github.com> Date: Mon, 12 Aug 2024 09:27:06 +0100 Subject: [PATCH 10/64] adding health warning about insecure protocols for LOAD CSV (#1006) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit adds a warning against allowing insecure protocols for `LOAD CSV` this PR is the docs counterpart to https://github.com/neo-technology/neo4j/pull/26403 I will add a duplicate warning to https://neo4j.com/docs/cypher-manual/current/clauses/load-csv/ https://neo4j.com/docs/operations-manual/5/authentication-authorization/load-privileges/ and possibly https://neo4j.com/docs/getting-started/data-import/csv-import/ once the wording of this one is finalised. --------- Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- modules/ROOT/pages/clauses/load-csv.adoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/ROOT/pages/clauses/load-csv.adoc b/modules/ROOT/pages/clauses/load-csv.adoc index a67c11b2a..2880d2526 100644 --- a/modules/ROOT/pages/clauses/load-csv.adoc +++ b/modules/ROOT/pages/clauses/load-csv.adoc @@ -90,6 +90,15 @@ You can import data from a CSV file hosted on a remote path. `LOAD CSV` supports accessing CSV files via HTTPS, HTTP, and FTP (with or without credentials). It also follows redirects, except those changing the protocol (for security reasons). +[IMPORTANT] +==== +It is strongly recommended to permit resource loading only over secure protocols such as HTTPS instead of insecure protocols like HTTP. +This can be done by limiting the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/load-privileges/#access-control-load-cidr/[load privileges] to only trusted sources that use secure protocols. +If allowing an insecure protocol is absolutely unavoidable, Neo4j takes measures internally to enhance the security of these requests within their limitations. +However, this means that insecure URLs on virtual hosts will not function unless you add the JVM argument `-Dsun.net.http.allowRestrictedHeaders=true` to the configuration setting link:{neo4j-docs-base-uri}/operations-manual/{page-version}/configuration/configuration-settings/#config_server.jvm.additional/[jvm.additional]. +==== + + .Import artists name and year information from a remote file via HTTPS ==== From 750a641f579a011b8075f96657dc33604bd85c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Mon, 12 Aug 2024 10:38:02 +0200 Subject: [PATCH 11/64] fix GQL table and update on CALL (#1018) --- .../pages/appendix/gql-conformance/index.adoc | 2 +- .../gql-conformance/supported-mandatory.adoc | 17 ----------------- .../gql-conformance/supported-optional.adoc | 11 +++++++++-- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/modules/ROOT/pages/appendix/gql-conformance/index.adoc b/modules/ROOT/pages/appendix/gql-conformance/index.adoc index 9448c41c4..e5743548f 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/index.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/index.adoc @@ -1,7 +1,7 @@ :description: Overview of Cypher's conformance to GQL. = GQL conformance -*Last updated*: 8 August 2024 + +*Last updated*: 9 August 2024 + *Neo4j version*: 5.23 GQL is the new link:https://www.iso.org/home.html[ISO] International Standard query language for graph databases. diff --git a/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc b/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc index 4d4ee103d..478988f85 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc @@ -71,23 +71,6 @@ The only way to guarantee row order in Neo4j is to use xref:clauses/order-by.ado | xref:clauses/return.adoc[`RETURN`] | -| 15.1 -| and -| xref:clauses/call.adoc[`CALL` procedures], xref:subqueries/call-subquery.adoc[`CALL` subqueries]. -| GQL defines an `OPTIONAL CALL` statement, enabling optional procedure and subquery calling. -This is not available in Cypher. - -| 15.2 -| -| xref:subqueries/call-subquery.adoc[`CALL` subqueries]. -| GQL either imports variables implicitly, or explicitly using a variable scope clause. -In Cypher, it is currently not possible to implicitly import variables. - -| 15.3 -| -| xref:clauses/call.adoc[`CALL` procedure] -| - | 16.2 | | xref:clauses/limit.adoc[`LIMIT`] diff --git a/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc b/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc index c8c76ab6c..b71364b84 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc @@ -130,11 +130,18 @@ In Cypher, `trim()` removes any whitespace character. | | GP01 -| xref:subqueries/call-subquery.adoc[Inline procedure] +| Inline procedure +| xref:subqueries/call-subquery.adoc[`CALL` subqueries] | | GP03 -| xref:subqueries/call-subquery.adoc#variable-scope-clause[Inline procedure with explicit nested variable scope] +| Inline procedure with explicit nested variable scope +| xref:subqueries/call-subquery.adoc#variable-scope-clause[`CALL` subqueries -> Variable scope clause] +| + +| GP04 +| Named procedure calls +| xref:clauses/call.adoc[`CALL` procedure] | | GQ01 From e6d0a2768e24a15e84e49f031ee902679b2c7f25 Mon Sep 17 00:00:00 2001 From: Phil Wright <95368282+phil198@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:18:57 +0100 Subject: [PATCH 12/64] link description correction (#1020) correcting link text to match https://github.com/neo4j/docs-getting-started/pull/410#discussion_r1713782822 --- modules/ROOT/pages/clauses/load-csv.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/pages/clauses/load-csv.adoc b/modules/ROOT/pages/clauses/load-csv.adoc index 2880d2526..fd19b94e7 100644 --- a/modules/ROOT/pages/clauses/load-csv.adoc +++ b/modules/ROOT/pages/clauses/load-csv.adoc @@ -95,7 +95,7 @@ It also follows redirects, except those changing the protocol (for security reas It is strongly recommended to permit resource loading only over secure protocols such as HTTPS instead of insecure protocols like HTTP. This can be done by limiting the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/load-privileges/#access-control-load-cidr/[load privileges] to only trusted sources that use secure protocols. If allowing an insecure protocol is absolutely unavoidable, Neo4j takes measures internally to enhance the security of these requests within their limitations. -However, this means that insecure URLs on virtual hosts will not function unless you add the JVM argument `-Dsun.net.http.allowRestrictedHeaders=true` to the configuration setting link:{neo4j-docs-base-uri}/operations-manual/{page-version}/configuration/configuration-settings/#config_server.jvm.additional/[jvm.additional]. +However, this means that insecure URLs on virtual hosts will not function unless you add the JVM argument `-Dsun.net.http.allowRestrictedHeaders=true` to the configuration setting link:{neo4j-docs-base-uri}/operations-manual/{page-version}/configuration/configuration-settings/#config_server.jvm.additional/[`server.jvm.additional`]. ==== From d4ec5de74a73603720bbbbbff427c61c9aef23b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:25:39 +0200 Subject: [PATCH 13/64] Remove Enterprise Edition label from GenAI plugin page (#1019) --- modules/ROOT/pages/genai-integrations.adoc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/genai-integrations.adoc b/modules/ROOT/pages/genai-integrations.adoc index 0ffed1b6d..5168f0d01 100644 --- a/modules/ROOT/pages/genai-integrations.adoc +++ b/modules/ROOT/pages/genai-integrations.adoc @@ -1,11 +1,12 @@ :description: Information about Neo4j's GenAI integrations. -:page-role: enterprise-edition new-5.17 +:page-role: new-5.17 :test-setup-dump: https://github.com/neo4j-graph-examples/recommendations/raw/main/data/recommendations-50.dump include::https://raw.githubusercontent.com/neo4j-graphacademy/courses/main/asciidoc/courses/llm-fundamentals/ad.adoc[] [[genai-integrations]] = GenAI integrations + Neo4j's xref:indexes/semantic-indexes/vector-indexes.adoc[] and xref:functions/vector.adoc[] allow you to calculate the similarity between node and relationship properties in a graph. A prerequisite for using these features is that vector embeddings have been set as properties of these entities. The GenAI plugin enables the creation of such embeddings using GenAI providers. @@ -20,10 +21,13 @@ For a hands-on guide on how to use the GenAI plugin, see link:https://neo4j.com/ The GenAI plugin is enabled by default in Neo4j Aura. -For self-managed instances, the plugin is only available on Enterprise Edition and needs to be installed. +The plugin needs to be installed on self-managed instances. This is done by moving the `neo4j-genai.jar` file from `/products` to `/plugins` in the Neo4j home directory, or, if you are using Docker, by starting the Docker container with the extra parameter `--env NEO4J_PLUGINS='["genai"]'`. For more information, see link:{neo4j-docs-base-uri}/operations-manual/{page-version}/configuration/plugins/[Operations Manual -> Configure plugins]. +[NOTE] +Prior to Neo4j 5.23, the GenAI plugin was only available on Neo4j Enterprise Edition. + [[example-graph]] == Example graph From 63475f5833e32a0fb3e2ec59147481ddd98b2483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 13 Aug 2024 14:20:23 +0200 Subject: [PATCH 14/64] Update GQL wording (#1021) --- modules/ROOT/pages/appendix/gql-conformance/index.adoc | 4 ++-- .../pages/appendix/gql-conformance/unsupported-mandatory.adoc | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/appendix/gql-conformance/index.adoc b/modules/ROOT/pages/appendix/gql-conformance/index.adoc index e5743548f..5b58aafb1 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/index.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/index.adoc @@ -20,8 +20,8 @@ RETURN m.title ---- Cypher supports the majority of mandatory GQL features. -For a full list, see xref:appendix/gql-conformance/supported-mandatory.adoc[]. -There are, however, currently a few mandatory GQL features not implemented in Cypher. +For a full list see xref:appendix/gql-conformance/supported-mandatory.adoc[]. +There are, however, currently a few mandatory GQL features not yet in Cypher that Neo4j is actively working towards implementing. These are listed in the page xref:appendix/gql-conformance/unsupported-mandatory.adoc[]. Neo4j is also working towards increasing its support of optional GQL features. diff --git a/modules/ROOT/pages/appendix/gql-conformance/unsupported-mandatory.adoc b/modules/ROOT/pages/appendix/gql-conformance/unsupported-mandatory.adoc index 3ff2558b2..98c143dcb 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/unsupported-mandatory.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/unsupported-mandatory.adoc @@ -1,7 +1,8 @@ :description: Information about mandatory GQL features not currently supported by Cypher. = Currently unsupported mandatory GQL features -Cypher supports most mandatory GQL features, though there are a few instances where its current functionality diverges. +Cypher supports most mandatory GQL features. +There are, however, currently a few mandatory GQL features not yet in Cypher that Neo4j is actively working towards implementing. The table below provides an overview of these GQL features and, where applicable, their functional equivalents in Neo4j. Unlike optional GQL features, mandatory GQL features are not assigned a GQL feature ID code. From e3ce55fdb4ad6d614dfe3d7c47030d066dc426c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:18:43 +0200 Subject: [PATCH 15/64] Update remaining queries using shortestPath() (#1022) --- modules/ROOT/pages/queries/basic.adoc | 39 +++++++++++++++--------- modules/ROOT/pages/queries/concepts.adoc | 6 ++-- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/modules/ROOT/pages/queries/basic.adoc b/modules/ROOT/pages/queries/basic.adoc index 7a73dfa20..530e50616 100644 --- a/modules/ROOT/pages/queries/basic.adoc +++ b/modules/ROOT/pages/queries/basic.adoc @@ -795,32 +795,43 @@ LIMIT 5 |=== [NOTE] -==== The quantifier used in the above two examples was introduced with the release of xref::patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path patterns] in Neo4j 5.9. Before that, the only way in Cypher to match paths of a variable length was with a variable-length relationship. -This syntax is still available in Cypher. -Read more about it xref::patterns/reference.adoc#variable-length-relationships[here]. -==== +This syntax is still available in Cypher, but it is not xref:appendix/gql-conformance/index.adoc[GQL conformant]. +For more information, see xref::patterns/reference.adoc#variable-length-relationships[Patterns -> Syntax and semantics -> Variable length relationships]. -To find the shortest possible path between two nodes, use the `shortestPath` algorithm. -For example, this query matches the shorest path in the graph between the two nodes `Tom Hanks` and `Keanu Reeves`: +The xref:patterns/shortest-paths.adoc[`SHORTEST`] keyword can be used to find a variation of the shortest paths between two nodes. +In this example, `ALL SHORTEST` paths between the two nodes `Keanu Reeves` and `Tom Cruise` are found. +The xref:functions/aggregating.adoc#functions-count[`count()`] function calculates the number of these shortest paths while the xref:functions/scalar.adoc#functions-length[`length()`] function calculates the length of each path in terms of traversed relationships. .Query [source, cypher] ---- -MATCH p=shortestPath( -(:Person {name:"Keanu Reeves"})-[*]-(:Person {name:"Tom Hanks"}) -) -RETURN p +MATCH p = ALL SHORTEST (:Person {name:"Keanu Reeves"})--+(:Person {name:"Tom Cruise"}) +RETURN count(p) AS pathCount, length(p) AS pathLength ---- -This is the returned path: +The results show that 2 different paths are tied for the shortest length. -image::introduction_example2.svg[width="500",role="middle] +.Result +[role="queryresult",options="header,footer",cols="2* Syntax and semantics -> The `shortestPath()` and `allShortestPaths()` functions]. -More information can be found in the section on xref::patterns/index.adoc[Patterns]. +For more information about graph pattern matching, see xref::patterns/index.adoc[Patterns]. [[find-recommendations]] == Finding recommendations diff --git a/modules/ROOT/pages/queries/concepts.adoc b/modules/ROOT/pages/queries/concepts.adoc index cc7b37d47..f0caa0fd8 100644 --- a/modules/ROOT/pages/queries/concepts.adoc +++ b/modules/ROOT/pages/queries/concepts.adoc @@ -71,13 +71,13 @@ This example uses a xref:patterns/variable-length-patterns.adoc#quantified-relat The xref:syntax/operators.adoc#syntax-using-the-distinct-operator[DISTINCT] operator is used to ensure that the `RETURN` clause only returns unique nodes. Paths can also be assigned variables. -For example, the below query binds a whole path pattern, which matches the xref:patterns/reference.adoc#shortest-functions[shortest path] from `Anna` to another `Person` node in the graph up to `10` hops away with the `nationality` property set to `Canadian`. +For example, the below query binds a whole path pattern, which matches the xref:patterns/shortest-paths.adoc[`SHORTEST`] path from `Anna` to another `Person` node in the graph with a `nationality` property set to `Canadian`. In this case, the `RETURN` clause returns the full path between the two nodes. [source, cypher] ---- -MATCH p=shortestPath((:Person {name: 'Anna'})-[:KNOWS*1..10]-(:Person {nationality: 'Canadian'})) +MATCH p = SHORTEST 1 (:Person {name: 'Anna'})-[:KNOWS]-+(:Person {nationality: 'Canadian'}) RETURN p ---- -For more information about graph patterns, see the section on xref:patterns/index.adoc[]. +For more information about graph pattern matching, see xref:patterns/index.adoc[]. From 8df83edea6ea85cf3a2dca0ce05dbf17b66aab12 Mon Sep 17 00:00:00 2001 From: Matthew Parnell Date: Fri, 16 Aug 2024 10:37:58 +0100 Subject: [PATCH 16/64] Add new vector index settings (#1009) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have exposed quantization, and `M` and `efConstruction` hyperparameters for the vector index. We have also allowed the similarity function to be defaulted to `'cosine'`, and for the dimensions to not need to be specified. --------- Co-authored-by: Richard Sill <156673635+rsill-neo4j@users.noreply.github.com> Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- ...ions-additions-removals-compatibility.adoc | 25 ++++ .../semantic-indexes/vector-indexes.adoc | 107 +++++++++++++++--- modules/ROOT/pages/indexes/syntax.adoc | 11 +- 3 files changed, 123 insertions(+), 20 deletions(-) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index 83437bedb..e93567124 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -85,6 +85,31 @@ RETURN x, y | Introduced a new xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] to import variables in `CALL` subqueries. +a| +label:functionality[] +label:new[] +[source, cypher, role=noheader] +---- +CREATE VECTOR INDEX moviePlots IF NOT EXISTS +FOR (m:Movie) +ON m.embedding +OPTIONS {indexConfig: { +`vector.quantization.enabled`: true +`vector.hnsw.m`: 16, +`vector.hnsw.ef_construction`: 100, +}} +---- + +a| Introduced the following xref:indexes/semantic-indexes/vector-indexes.adoc#configuration-settings[configuration settings] for vector indexes: + +* `vector.quantization.enabled`: allows for enabling quantization, which can accelerate search performance but can also slightly decrease accuracy. + +* `vector.hnsw.m`: controls the maximum number of connections each node has in the index's internal graph. + +* `vector.hnsw.ef_construction`: sets the number of nearest neighbors tracked during the insertion of vectors into the index's internal graph. + +Additionally, as of Neo4j 5.23, it is no longer mandatory to configure the settings `vector.dimensions` and `vector.similarity_function` when creating a vector index. + |=== [[cypher-deprecations-additions-removals-5.21]] diff --git a/modules/ROOT/pages/indexes/semantic-indexes/vector-indexes.adoc b/modules/ROOT/pages/indexes/semantic-indexes/vector-indexes.adoc index c8bedbc44..6029c675c 100644 --- a/modules/ROOT/pages/indexes/semantic-indexes/vector-indexes.adoc +++ b/modules/ROOT/pages/indexes/semantic-indexes/vector-indexes.adoc @@ -92,7 +92,7 @@ Creating indexes requires link:{neo4j-docs-base-uri}/operations-manual/{page-ver CREATE VECTOR INDEX moviePlots IF NOT EXISTS // <1> FOR (m:Movie) ON m.embedding -OPTIONS {indexConfig: { +OPTIONS { indexConfig: { `vector.dimensions`: 1536, `vector.similarity_function`: 'cosine' }} // <2> @@ -103,8 +103,10 @@ This means that its default behavior is to throw an error if an attempt is made With `IF NOT EXISTS`, no error is thrown and nothing happens should an index with the same name, schema or both already exist. It may still throw an error should a constraint with the same name exist. As of Neo4j 5.17, an informational notification is returned when nothing happens, showing the existing index which blocks the creation. -<2> The `OPTIONS` map is mandatory since a vector index cannot be created without setting the vector dimensions and similarity function. -In this example, the vector dimension is set to `1536` and the vector similarity function is `cosine`, which is generally the preferred similarity function for text embeddings. +<2> Prior to Neo4j 5.23, the `OPTIONS` map was mandatory since a vector index could not be created without setting the vector dimensions and similarity function. +Since Neo4j 5.23, both can be omitted. +To read more about the available configuration settings, see xref:indexes/semantic-indexes/vector-indexes.adoc#configuration-settings[]. +In this example, the vector dimension is explicitly set to `1536` and the vector similarity function to `'cosine'`, which is generally the preferred similarity function for text embeddings. To read more about the available similarity functions, see xref:indexes/semantic-indexes/vector-indexes.adoc#similarity-functions[]. [NOTE] @@ -117,12 +119,78 @@ You can also create a vector index for relationships with a particular type on a ---- CREATE VECTOR INDEX name IF NOT EXISTS FOR ()-[r:REL_TYPE]-() ON (r.embedding) -OPTIONS {indexConfig: { +OPTIONS { indexConfig: { `vector.dimensions`: $dimension, `vector.similarity_function`: $similarityFunction }} ---- +[[configuration-settings]] +=== Configuration settings + +For more information about the values accepted by different index providers, see xref:indexes/semantic-indexes/vector-indexes.adoc#vector-index-providers[]. + +[[config-vector-dimensions]] +==== `vector.dimensions` +The dimensions of the vectors to be indexed. +For more information, see xref:indexes/semantic-indexes/vector-indexes.adoc#embeddings[]. +This setting can be omitted, and any `LIST` can be indexed and queried, separated by their dimensions, _though only vectors of the same dimension can be compared._ +Setting this value adds additional checks that ensure only vectors with the configured dimensions are indexed, and querying the index with a vector of a different dimensions returns an error. + +[NOTE] +It is recommended to provide dimensions when creating a vector index. + +Accepted values::: `INTEGER` between `1` and `4096` inclusively. +Default value::: None. +The setting was mandatory prior to Neo4j 5.23. + +[[config-vector-similarity-function]] +==== `vector.similarity_function` + +The name of the similarity function used to assess the similarity of two vectors. +To read more about the available similarity functions, see xref:indexes/semantic-indexes/vector-indexes.adoc#similarity-functions[]. + +Accepted values::: `STRING`: `'cosine'`, `'euclidean'`. +Default value::: `'cosine'`. The setting was mandatory prior to Neo4j 5.23. + +[role=label--new-5.23] +[[config-vector-quantization]] +==== `vector.quantization.enabled` + +Quantization is a technique to reduce the size of vector representations. +Enabling quantization can accelerate search performance but can slightly decrease accuracy. +It is recommended to enable quantization on machines with limited memory. +Vector indexes created prior to Neo4j 5.23 have this setting effectively set to `false`. + +Accepted values::: `BOOLEAN`: `true`, `false`. +Default value::: `true` + +[discrete] +[[config-advanced]] +=== Advanced configuration settings + +[role=label--new-5.23] +[[config-vector-hsnw.m]] +==== `vector.hnsw.m` + +The `M` parameter controls the maximum number of connections each node has in the HNSW (Hierarchical Navigable Small Worlds) graph. +Increasing this value may lead to greater accuracy at the expense of increased index population and update times, especially for vectors with high dimensionality. +Vector indexes created prior to Neo4j 5.23 have this setting effectively set to `16`. + +Accepted values::: `INTEGER` between `1` and `512` inclusively. +Default value::: `16` + +[role=label--new-5.23] +[[config-vector-hsnw.ef_construction]] +==== `vector.hnsw.ef_construction` + +The number of nearest neighbors tracked during the insertion of vectors into the HNSW graph. +Increasing this value increases the quality of the index, and may lead to greater accuracy (with diminishing returns) at the expense of increased index population and update times. +Vector indexes created prior to Neo4j 5.23 have this setting effectively set to `100`. + +Accepted values::: `INTEGER` between `1` and `3200` inclusively. +Default value::: `100` + [[query-vector-index]] == Query vector indexes @@ -159,8 +227,8 @@ RETURN movie.title AS title, movie.plot AS plot, score | "Godfather, The" | "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son." | 1.0 | | "Godfather: Part III, The" | "In the midst of trying to legitimize his business dealings in New York and Italy in 1979, aging Mafia don Michael Corleone seeks to avow for his sins while taking a young protégé under his wing." | 0.9648237228393555 | | "Godfather: Part II, The" | "The early life and career of Vito Corleone in 1920s New York is portrayed while his son, Michael, expands and tightens his grip on his crime syndicate stretching from Lake Tahoe, Nevada to pre-revolution 1958 Cuba." | 0.9547788500785828 | +| "Goodfellas" | "Henry Hill and his friends work their way up through the mob hierarchy." | 0.9300689697265625 | | "Scarface" | "An ambitious and near insanely violent gangster climbs the ladder of success in the mob, but his weaknesses prove to be his downfall." | 0.9367183446884155 | -| "Jane Austen's Mafia!" | "Takeoff on the Godfather with the son of a mafia king taking over for his dying father" | 0.9366795420646667 | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ---- @@ -238,11 +306,11 @@ SHOW VECTOR INDEXES YIELD * .Result [source, role=queryresult] ---- -+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| id | name | state | populationPercent | type | entityType | labelsOrTypes | properties | indexProvider | owningConstraint | lastRead | readCount | trackedSince | options | failureMessage | createStatement | -+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 2 | "moviePlots" | "ONLINE" | 100.0 | "VECTOR" | "NODE" | ["Movie"] | ["embedding"] | "vector-2.0" | NULL | 2024-05-07T09:19:09.225Z | 47 | 2024-05-07T08:26:19.072Z | {indexConfig: {`vector.dimensions`: 1536, `vector.similarity_function`: "COSINE"}, indexProvider: "vector-2.0"} | "" | "CREATE VECTOR INDEX `moviePlots` FOR (n:`Movie`) ON (n.`embedding`) OPTIONS {indexConfig: {`vector.dimensions`: 1536,`vector.similarity_function`: 'COSINE'}, indexProvider: 'vector-2.0'}" | -+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| id | name | state | populationPercent | type | entityType | labelsOrTypes | properties | indexProvider | owningConstraint| lastRead | readCount | trackedSince | options | failureMessage | createStatement | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 2 | "moviePlots"| "ONLINE" | 100.0 | "VECTOR" | "NODE" | ["Movie"] | ["embedding"] | "vector-2.0" | NULL | 2024-05-07T09:19:09.225Z | 47 | 2024-05-07T08:26:19.072Z | {indexConfig: {indexConfig: {`vector.dimensions`: 1536, `vector.hnsw.m`: 16, `vector.quantization.enabled`: TRUE, `vector.similarity_function`: "COSINE", `vector.hnsw.ef_construction`: 100}, indexProvider: "vector-2.0"}, indexProvider: "vector-2.0"} | "" | "CREATE VECTOR INDEX `moviePlots` FOR (n:`Movie`) ON (n.`embedding`) OPTIONS {indexConfig: {`vector.dimensions`: 1536,`vector.hnsw.ef_construction`: 100,`vector.hnsw.m`: 16,`vector.quantization.enabled`: true,`vector.similarity_function`: 'COSINE'}, indexProvider: 'vector-2.0'}" | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ---- To return only specific details, specify the desired column name(s) after the `YIELD` clause. @@ -367,7 +435,7 @@ Cosine similarity is used when the _angle_ between the vectors is what determine A valid vector for a cosine vector index is when: -* All vector components can be represented finitely in IEEE 754 double precision. +* All vector components can be represented finitely in IEEE 754 double precision.footnote:[link:https://ieeexplore.ieee.org/document/8766229[IEEE Standard for Floating-Point Arithmetic]] * Its {l2-norm} is non-zero and can be represented finitely in IEEE 754 double precision. * The ratio of each vector component with its {l2-norm} can be represented finitely in IEEE 754 single precision. @@ -386,7 +454,7 @@ In the above equation the trigonometric cosine is given by the scalar product of ==== Euclidean similarity is useful when the _distance_ between the vectors is what determines how similar two vectors are. -A valid vector for a Euclidean vector index is when all vector components can be represented finitely in IEEE 754 single precision.footnote:[link:https://ieeexplore.ieee.org/document/8766229[IEEE Standard for Floating-Point Arithmetic]] +A valid vector for a Euclidean vector index is when all vector components can be represented finitely in IEEE 754 single precision. Euclidean interprets the vectors in Cartesian coordinates. The measure is related to the Euclidean distance, i.e., how far two points are from one another. @@ -449,8 +517,6 @@ The requested _k_ nearest neighbors may not be the exact _k_ nearest, but close * Only one vector index can be over a schema. For example, you cannot have one xref:indexes/semantic-indexes/vector-indexes.adoc#similarity-functions[Euclidean] and one xref:indexes/semantic-indexes/vector-indexes.adoc#similarity-functions[cosine] vector index on the same label-property key pair. -* No provided settings or options for tuning the index. - * Changes made within the same transaction are not visible to the index. ==== @@ -463,6 +529,15 @@ The following table lists the known issues and, if fixed, the version in which t |=== | Known issues | Fixed in +| The creation of a vector index using the legacy procedure link:{neo4j-docs-base-uri}/operations-manual/{page-version}/reference/procedures/#procedure_db_index_vector_createnodeindex[`db.index.vector.createNodeIndex`] may fail with an error in Neo4j 5.18 and later if the database was last written to with a version prior to Neo4j 5.11, and the legacy procedure is the first write operation used on the newer version. +In Neo4j 5.20, the error was clarified. +[TIP] +-- +Using the `CREATE VECTOR INDEX` command instead avoids this issue. +If the use of the procedure is unavoidable, performing any other write operation to the database on the newer binary before using the procedure will avoid the issue +-- +| + | Procedure signatures from `SHOW PROCEDURES` will render the vector arguments with a type of `ANY` rather than the semantically correct type of `LIST`. [NOTE] -- @@ -470,11 +545,13 @@ The types are still enforced as `LIST`. -- | +| No provided settings or options for tuning the index. +| Neo4j 5.23 + | Only node vector indexes are supported. | Neo4j 5.18 | Vector indexes cannot be assigned autogenerated names. - | Neo4j 5.15 | There is no Cypher syntax for creating a vector index. diff --git a/modules/ROOT/pages/indexes/syntax.adoc b/modules/ROOT/pages/indexes/syntax.adoc index 1eb27c3c8..baede5cba 100644 --- a/modules/ROOT/pages/indexes/syntax.adoc +++ b/modules/ROOT/pages/indexes/syntax.adoc @@ -207,17 +207,18 @@ ON (r.propertyName) [OPTIONS “{“ option: value[, …] “}”] ---- -Vector indexes have two settings, `vector.dimensions` and `vector.similarity_function`, which have no default values. -As of Neo4j 5.18, they have two index providers available, `vector-2.0` (default) and `vector-1.0`. +As of Neo4j 5.18, vector indexes have two vector index providers available, `vector-2.0` (default) and `vector-1.0`. +For more information, see xref:indexes/semantic-indexes/vector-indexes.adoc#vector-index-providers[Vector index providers for compatibility]. -The `OPTIONS` clause is mandatory when creating a vector index, because it is necessary to configure the `vector.dimensions` and `vector.similarity_function` settings: +For a full list of all vector index settings, see xref:indexes/semantic-indexes/vector-indexes.adoc#configuration-settings[Vector index configuration settings]. +Note that the `OPTIONS` clause was mandatory prior to Neo4j 5.23 because it was necessary to configure the `vector.dimensions` and `vector.similarity_function` settings when creating a vector index. [source,syntax] ---- OPTIONS { indexConfig: { `vector.dimensions`: $dimension, - `vector.similarity_function`: $similarityFunction + `vector.similarity_function`: $similarityFunction } } ---- @@ -225,7 +226,7 @@ OPTIONS { [NOTE] It is not possible to create composite vector indexes on multiple properties. -For more information, see xref:indexes/semantic-indexes/vector-indexes.adoc#indexes-vector-create[Vector indexes - Create and configure vector indexes]. +For more information, see xref:indexes/semantic-indexes/vector-indexes.adoc#create-vector-index[Vector indexes - Create and configure vector indexes]. [[list-index]] == SHOW INDEX From a85c9fef121dfac5d6b37e88f7fc0d4579ae421c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:53:18 +0200 Subject: [PATCH 17/64] Correct documentation on comparing spatial values (#1023) --- .../deprecations-additions-removals-compatibility.adoc | 2 +- modules/ROOT/pages/syntax/operators.adoc | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index e93567124..cb7621548 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -2139,7 +2139,7 @@ label:removed[] point({x:0, y:0}) <= point({x:1, y:1}) <= point({x:2, y:2}) ---- a| -The ability to use operators `<`, `<=`, `>`, and `>=` on spatial points is removed. +The ability to use operators `<`, `+<=+`, `>`, or `>=` on spatial points is removed. Instead, use: [source, cypher, role="noheader"] ---- diff --git a/modules/ROOT/pages/syntax/operators.adoc b/modules/ROOT/pages/syntax/operators.adoc index c5e8075cf..b6ce384ab 100644 --- a/modules/ROOT/pages/syntax/operators.adoc +++ b/modules/ROOT/pages/syntax/operators.adoc @@ -359,11 +359,9 @@ The following points give some details on how the comparison is performed. For example, `1 > b` and `1 < b` are both false when b is NaN. * String values are compared for ordering using lexicographic order (e.g. `"x" < "xy"`). * Boolean values are compared for ordering such that `false < true`. -* *Comparison* of spatial values: - ** Point values can only be compared within the same Coordinate Reference System (CRS) -- otherwise, the result will be `null`. - ** For two points `a` and `b` within the same CRS, `a` is considered to be greater than `b` if `a.x > b.x` and `a.y > b.y` (and `a.z > b.z` for 3D points). - ** `a` is considered less than `b` if `a.x < b.x` and `a.y < b.y` (and `a.z < b.z` for 3D points). - ** If none if the above is true, the points are considered incomparable and any comparison operator between them will return `null`. +* Spatial values cannot be compared using the operators `<`, `+<=+`, `>`, or `>=`. +To compare spatial values within a specific range, use either the xref:functions/spatial.adoc#functions-withinBBox[`point.withinBBox()`] or the xref:functions/spatial.adoc#functions-point-wgs84-2d[`point()`] function. + * *Ordering* of spatial values: ** `ORDER BY` requires all values to be orderable. ** Points are ordered after arrays and before temporal types. From 05aca7fe721c36e0e4e3002433d92fc74d35ea8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Mon, 19 Aug 2024 19:40:30 +0200 Subject: [PATCH 18/64] Add information about Text indexes and dictionary variables (#1026) --- .../using-indexes.adoc | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc b/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc index cc7b4f263..4969df552 100644 --- a/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc +++ b/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc @@ -235,7 +235,6 @@ Text indexes do not store `STRING` properties alphabetically, and are instead op That said, if no range index had been present on the name property, the previous query would still have been able to utilize the text index. It would have done so less efficiently than a range index, but it still would have been useful. - For more information about range index ordering, see the section on xref:indexes/search-performance-indexes/using-indexes.adoc#range-index-backed-order-by[Range index-backed ORDER BY]. [TIP] @@ -243,6 +242,28 @@ Text indexes are only used for exact query matches. To perform approximate match For more information about the predicates supported by text indexes, see xref:indexes/search-performance-indexes/managing-indexes.adoc#text-indexes-supported-predicates[Create, show, and delete indexes -> Text indexes: supported predicates]. +[[text-index-dictionary-variables]] +=== Ensuring text index use + +In order for the planner to use text indexes, it must be able to confirm that the properties included in the predicate are `STRING` values. +This is not possible when accessing property values within nodes or relationships, or values within a `MAP`, since Cypher does not store the type information of these values. +To ensure text indexes are used in these cases, the xref:functions/string.adoc#functions-tostring[`toString`] function should be used. + +.Text index not used +[source,cypher] +---- +WITH {name: 'William Shakespeare'} AS varName +MERGE (:PointOfInterest {name:varName.name}) +---- + +.Text index used +[source,cypher] +---- +WITH {name: 'William Shakespeare'} AS varName +MERGE (ws:PointOfInterest {name: toString(varName.name)}) +---- + +For information about how to ensure the use of text indexes when predicates may contain `null` values, see xref:indexes/search-performance-indexes/using-indexes/indexes-and-null[Indexes and `null` values]. [[text-index-string-size]] === Text indexes and `STRING` sizes From bd39e671253a7c0acefd9ff5e364428f46bafbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 20 Aug 2024 08:36:52 +0200 Subject: [PATCH 19/64] Add alias for index page (#1029) --- .../indexes/search-performance-indexes/using-indexes.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc b/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc index 4969df552..bcf88382b 100644 --- a/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc +++ b/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc @@ -1,6 +1,7 @@ :description: Information about how search-performance indexes impact query performance in Neo4j. :test-setup-dump: https://github.com/neo4j-graph-examples/openstreetmap/raw/main/data/openstreetmap-50.dump include::https://raw.githubusercontent.com/neo4j-graphacademy/courses/main/asciidoc/courses/cypher-indexes-constraints/ad.adoc[] +:page-aliases: query-tuning/indexes.adoc = The impact of indexes on query performance @@ -260,7 +261,7 @@ MERGE (:PointOfInterest {name:varName.name}) [source,cypher] ---- WITH {name: 'William Shakespeare'} AS varName -MERGE (ws:PointOfInterest {name: toString(varName.name)}) +MERGE (:PointOfInterest {name: toString(varName.name)}) ---- For information about how to ensure the use of text indexes when predicates may contain `null` values, see xref:indexes/search-performance-indexes/using-indexes/indexes-and-null[Indexes and `null` values]. From dd11ea84bc5ebd035e0db40397ab7bc0912da53e Mon Sep 17 00:00:00 2001 From: Matthew Parnell Date: Tue, 20 Aug 2024 10:58:36 +0100 Subject: [PATCH 20/64] normalise vector index settings achors (#1030) There were a mix of - _ . being used in the new sections, and some omitted parts of the name, and felt a little inconsistent. This changes the new achors such that it would be #config-INDEXSETTING This is similar to how the Neo4j configuration settings are referenced in the operations manual. --- .../pages/indexes/semantic-indexes/vector-indexes.adoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/indexes/semantic-indexes/vector-indexes.adoc b/modules/ROOT/pages/indexes/semantic-indexes/vector-indexes.adoc index 6029c675c..13c8334b2 100644 --- a/modules/ROOT/pages/indexes/semantic-indexes/vector-indexes.adoc +++ b/modules/ROOT/pages/indexes/semantic-indexes/vector-indexes.adoc @@ -130,7 +130,7 @@ OPTIONS { indexConfig: { For more information about the values accepted by different index providers, see xref:indexes/semantic-indexes/vector-indexes.adoc#vector-index-providers[]. -[[config-vector-dimensions]] +[[config-vector.dimensions]] ==== `vector.dimensions` The dimensions of the vectors to be indexed. For more information, see xref:indexes/semantic-indexes/vector-indexes.adoc#embeddings[]. @@ -144,7 +144,7 @@ Accepted values::: `INTEGER` between `1` and `4096` inclusively. Default value::: None. The setting was mandatory prior to Neo4j 5.23. -[[config-vector-similarity-function]] +[[config-vector.similarity_function]] ==== `vector.similarity_function` The name of the similarity function used to assess the similarity of two vectors. @@ -154,7 +154,7 @@ Accepted values::: `STRING`: `'cosine'`, `'euclidean'`. Default value::: `'cosine'`. The setting was mandatory prior to Neo4j 5.23. [role=label--new-5.23] -[[config-vector-quantization]] +[[config-vector.quantization.enabled]] ==== `vector.quantization.enabled` Quantization is a technique to reduce the size of vector representations. @@ -170,7 +170,7 @@ Default value::: `true` === Advanced configuration settings [role=label--new-5.23] -[[config-vector-hsnw.m]] +[[config-vector.hsnw.m]] ==== `vector.hnsw.m` The `M` parameter controls the maximum number of connections each node has in the HNSW (Hierarchical Navigable Small Worlds) graph. @@ -181,7 +181,7 @@ Accepted values::: `INTEGER` between `1` and `512` inclusively. Default value::: `16` [role=label--new-5.23] -[[config-vector-hsnw.ef_construction]] +[[config-vector.hsnw.ef_construction]] ==== `vector.hnsw.ef_construction` The number of nearest neighbors tracked during the insertion of vectors into the HNSW graph. From ef93d827b8e39e9654b023c6640f628c5e33f789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:26:53 +0200 Subject: [PATCH 21/64] update antora for 5.24 (#1032) --- antora.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/antora.yml b/antora.yml index 3efd4c638..c48e579e0 100644 --- a/antora.yml +++ b/antora.yml @@ -7,5 +7,5 @@ nav: asciidoc: attributes: neo4j-version: '5' - neo4j-version-minor: '5.23' - neo4j-version-exact: '5.23.0' + neo4j-version-minor: '5.24' + neo4j-version-exact: '5.24.0' From 0ab44c109bf86546c9a5ef335dbfed2f7e45c843 Mon Sep 17 00:00:00 2001 From: Gem Lamont <106068376+gem-neo4j@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:38:18 +0200 Subject: [PATCH 22/64] Add docs on dynamic properties (#972) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- modules/ROOT/images/graph_remove_clause.svg | 55 +----- modules/ROOT/images/graph_set_clause.svg | 64 +------ modules/ROOT/pages/clauses/remove.adoc | 109 ++++++++++- modules/ROOT/pages/clauses/set.adoc | 177 +++++++++++++++++- ...ions-additions-removals-compatibility.adoc | 38 ++++ 5 files changed, 315 insertions(+), 128 deletions(-) diff --git a/modules/ROOT/images/graph_remove_clause.svg b/modules/ROOT/images/graph_remove_clause.svg index fccb1b2c7..534698e78 100644 --- a/modules/ROOT/images/graph_remove_clause.svg +++ b/modules/ROOT/images/graph_remove_clause.svg @@ -1,54 +1 @@ - - - - - - -L - - - -N0 - -Swedish - -age = 36 -name = 'Andy' - - - -N2 - -Swedish, German - -age = 34 -name = 'Peter' - - - -N0->N2 - - -KNOWS - - - -N1 - -Swedish - -age = 25 -name = 'Timothy' - - - -N0->N1 - - -KNOWS - - - +KNOWSKNOWSSwedishname:'Andy'age:36propTestValue2:42Swedishname:'Timothy'age:25propTestValue2:42SwedishGermanname:'Peter'age:34 \ No newline at end of file diff --git a/modules/ROOT/images/graph_set_clause.svg b/modules/ROOT/images/graph_set_clause.svg index 35e27e288..61126d48d 100644 --- a/modules/ROOT/images/graph_set_clause.svg +++ b/modules/ROOT/images/graph_set_clause.svg @@ -1,63 +1 @@ - - - - - - -L - - - -N0 - -Swedish - -name = 'Andy' -age = 36 -hungry = true - - - -N2 - -name = 'Peter' -age = 34 - - - -N0->N2 - - -KNOWS - - - -N1 - -name = 'Stefan' - - - -N1->N0 - - -KNOWS - - - -N3 - -name = 'George' - - - -N3->N2 - - -KNOWS - - - +KNOWSKNOWSKNOWSname:'Stefan'Swedishname:'Andy'age:36hungry:truename:'George'name:'Peter'age:34 \ No newline at end of file diff --git a/modules/ROOT/pages/clauses/remove.adoc b/modules/ROOT/pages/clauses/remove.adoc index 3df25fd26..4203403af 100644 --- a/modules/ROOT/pages/clauses/remove.adoc +++ b/modules/ROOT/pages/clauses/remove.adoc @@ -16,21 +16,23 @@ Removing labels from a node is an idempotent operation: if you try to remove a l The query statistics will tell you if something needed to be done or not. ==== -The examples use the following database: +== Example graph -image:graph_remove_clause.svg[] +The following graph is used for the examples below: + +image::graph_remove_clause.svg[width="600", role="middle"] + +To recreate it, run the following query against an empty Neo4j database: -//// [source, cypher, role=test-setup] ---- CREATE - (a:Swedish {name: 'Andy', age: 36}), - (t:Swedish {name: 'Timothy', age: 25}), + (a:Swedish {name: 'Andy', age: 36, propTestValue1: 42}), + (t:Swedish {name: 'Timothy', age: 25, propTestValue2: 42}), (p:German:Swedish {name: 'Peter', age: 34}), (a)-[:KNOWS]->(t), (a)-[:KNOWS]->(p) ---- -//// [[remove-remove-a-property]] @@ -66,6 +68,45 @@ Properties set: 1 `REMOVE` cannot be used to remove all existing properties from a node or relationship. Instead, using xref::clauses/set.adoc#set-remove-properties-using-empty-map[`SET` with `=` and an empty map as the right operand] will clear all properties from the node or relationship. +[role=label--new-5.24] +[[remove-remove-a-property-dynamically]] +== Dynamically removing a property + +`REMOVE` can be used to remove a property on a node or relationship even when the property key name is not statically known. + +[source, syntax] +---- +REMOVE n[key] +---- + +The dynamically calculated key must evaluate to a `STRING` value. +This query creates a copy of every property on the nodes: + + +.Query +[source, cypher, indent=0] +---- +MATCH (n) +WITH n, [k IN keys(n) WHERE k CONTAINS "Test" | k] as propertyKeys // <1> +FOREACH (i IN propertyKeys | REMOVE n[i]) // <2> +RETURN n.name, keys(n); +---- + +<1> The xref:functions/list.adoc#functions-keys[keys()] function retrieves all property keys of the matched nodes, and a xref:values-and-types/lists.adoc#cypher-list-comprehension[list comprehension] filters these keys to include only those that contain the substring "Test", assigning the resulting list to the variable `propertyKeys`. +<2> The xref:clauses/foreach.adoc[`FOREACH`] clause iterates over each key in the `propertyKeys` list and removes the corresponding property using the `REMOVE` clause. + +All properties with the word "Test" in them are removed: + +.Result +[role="queryresult",options="header,footer",cols="2* +REMOVE n:$(label) +RETURN n.name, labels(n) +---- + +<1> xref:clauses/unwind.adoc[`UNWIND`] is used here to transform the list of labels from the xref:functions/list.adoc#functions-labels[`labels()]` function into separate rows, allowing subsequent operations to be performed on each label individually. + +.Result +[role="queryresult",options="header,footer",cols="2*` and/or by chaining them separately with a `:`: + +.Query +[source, cypher, indent=0] +---- +MATCH (n {name: 'Peter'}) +REMOVE n:$(labels(n)) +RETURN n.name, labels(n) +---- + +.Result +[role="queryresult",options="header,footer",cols="2*(a), (d)-[:KNOWS]->(c) ---- -//// - [[set-set-a-property]] == Set a property @@ -160,6 +161,47 @@ Properties set: 1 |=== +[role=label--new-5.24] +[[set-dynamically-a-property]] +== Dynamically setting or updating a property + +`SET` can be used to set or update a property on a node or relationship even when the property key name is not statically known. + +[source, syntax] +---- +SET n[key] = expression +---- + +The dynamically calculated key must evaluate to a `STRING` value. +This query creates a copy of every property on the nodes: + +.Query +[source, cypher] +---- +MATCH (n) +FOREACH (k IN keys(n) | SET n[k + "Copy"] = n[k]) // <1> +RETURN n.name, keys(n); +---- + + +<1> The xref:clauses/foreach.adoc[`FOREACH`] clause iterates over each property key `k` obtained from the xref::functions/list.adoc#functions-keys[`keys()`] function. +For each key, it sets a new property on the nodes with a key name of `k` + "Copy" and copies the value from the original property. + +The nodes now have copies of all their properties. + +.Result +[role="queryresult",options="header,footer",cols="2*` and/or by chaining them separately with a `:`: + +.Query +[source, cypher] +---- +WITH COLLECT { UNWIND range(0,3) AS id RETURN "Label" + id } as labels // <1> +MATCH (n {name: 'George'}) +SET n:$(labels) +RETURN n.name, labels(n) AS labels +---- + +<1> A xref:subqueries/collect.adoc[`COLLECT`] subquery aggregates the results of `UNWIND range(0,3) AS id RETURN "Label" + id`, which generates a `LIST` strings ("Label0", "Label1", "Label2", "Label3"), and assigns it to the variable `labels`. + +The newly-labeled node is returned by the query. + +.Result +[role="queryresult",options="header,footer",cols="2* Date: Mon, 26 Aug 2024 08:47:16 +0200 Subject: [PATCH 23/64] Add note clarifying DELETE does not free up disk space (#1025) --- modules/ROOT/pages/clauses/delete.adoc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/clauses/delete.adoc b/modules/ROOT/pages/clauses/delete.adoc index c386f4175..0f6c13678 100644 --- a/modules/ROOT/pages/clauses/delete.adoc +++ b/modules/ROOT/pages/clauses/delete.adoc @@ -9,7 +9,11 @@ The `DELETE` clause is used to delete nodes, relationships or paths. For removing properties and labels, see the xref::clauses/remove.adoc[REMOVE] clause. It is not possible to delete nodes with relationships connected to them without also deleting the relationships. -This can be done by either explicitly deleting specific relationships, or by using the `DETACH DELETE` clause. +This can be done by either explicitly deleting specific relationships, or by using the `DETACH DELETE` clause. + +[NOTE] +While the `DELETE` clause renders the deleted objects no longer accessible, the space occupied by the deleted nodes and relationships remain on the disk and is reserved for future transactions creating data. +For information about how to clear and reuse the space occupied by deleted objects, see link:{neo4j-docs-base-uri}/operations-manual/{page-version}/performance/space-reuse/[Operations Manual -> Space reuse]. == Example graph From 99e9db5c373d0bbcc868207bcced4991cab8339c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:39:12 +0200 Subject: [PATCH 24/64] Add new Function detail tables (inluding new argument descriptions) (#1024) --- modules/ROOT/content-nav.adoc | 19 +- modules/ROOT/pages/functions/aggregating.adoc | 541 +- modules/ROOT/pages/functions/database.adoc | 18 +- modules/ROOT/pages/functions/graph.adoc | 57 +- modules/ROOT/pages/functions/index.adoc | 803 ++- modules/ROOT/pages/functions/list.adoc | 495 +- modules/ROOT/pages/functions/load-csv.adoc | 46 +- .../functions/mathematical-logarithmic.adoc | 177 +- .../pages/functions/mathematical-numeric.adoc | 436 +- .../functions/mathematical-trigonometric.adoc | 456 +- modules/ROOT/pages/functions/predicate.adoc | 335 +- modules/ROOT/pages/functions/scalar.adoc | 1044 +--- modules/ROOT/pages/functions/spatial.adoc | 580 +- modules/ROOT/pages/functions/string.adoc | 746 +-- .../pages/functions/temporal/duration.adoc | 413 +- .../ROOT/pages/functions/temporal/index.adoc | 4858 +++++------------ modules/ROOT/pages/functions/vector.adoc | 156 +- 17 files changed, 3335 insertions(+), 7845 deletions(-) diff --git a/modules/ROOT/content-nav.adoc b/modules/ROOT/content-nav.adoc index 5b947b624..f51ddf907 100644 --- a/modules/ROOT/content-nav.adoc +++ b/modules/ROOT/content-nav.adoc @@ -64,22 +64,23 @@ ** xref:values-and-types/type-predicate.adoc[] * xref:functions/index.adoc[] -** xref:functions/predicate.adoc[] -** xref:functions/scalar.adoc[] ** xref:functions/aggregating.adoc[] +** xref:functions/database.adoc[] +** xref:functions/graph.adoc[] ** xref:functions/list.adoc[] -** xref:functions/mathematical-numeric.adoc[] +** xref:functions/load-csv.adoc[] ** xref:functions/mathematical-logarithmic.adoc[] +** xref:functions/mathematical-numeric.adoc[] ** xref:functions/mathematical-trigonometric.adoc[] +** xref:functions/predicate.adoc[] +** xref:functions/scalar.adoc[] +** xref:functions/spatial.adoc[] ** xref:functions/string.adoc[] -** xref:functions/temporal/index.adoc[] ** xref:functions/temporal/duration.adoc[] -** xref:functions/spatial.adoc[] -** xref:functions/vector.adoc[] -** xref:functions/load-csv.adoc[] -** xref:functions/graph.adoc[] -** xref:functions/database.adoc[] +** xref:functions/temporal/index.adoc[] ** xref:functions/user-defined.adoc[] +** xref:functions/vector.adoc[] + * xref:genai-integrations.adoc[] * xref:indexes/index.adoc[] diff --git a/modules/ROOT/pages/functions/aggregating.adoc b/modules/ROOT/pages/functions/aggregating.adoc index 7df96e029..238404787 100644 --- a/modules/ROOT/pages/functions/aggregating.adoc +++ b/modules/ROOT/pages/functions/aggregating.adoc @@ -1,5 +1,6 @@ :description: Aggregating functions take a set of values and calculate an aggregated value over them. include::https://raw.githubusercontent.com/neo4j-graphacademy/courses/main/asciidoc/courses/cypher-aggregation/ad.adoc[] +:table-caption!: [[query-functions-aggregating]] = Aggregating functions @@ -38,36 +39,18 @@ CREATE ---- [[functions-avg]] -== avg() - Numeric values - -The function `avg()` returns the average of a set of `INTEGER` or `FLOAT` values. - -[source, syntax] ----- -avg(expression) ----- - -*Returns:* +== avg() +.Details |=== - -| Either an `INTEGER` or a `FLOAT`, depending on the values returned by `expression` and whether or not the calculation overflows. - -|=== - -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `expression` -| An expression returning a set of numeric values. - +| *Syntax* 3+| `avg(input)` +| *Description* 3+| Returns the average of a set of `INTEGER`, `FLOAT` or `DURATION` values. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `INTEGER \| FLOAT \| DURATION` | A value aggregated to form an average. +| *Returns* 3+| `INTEGER \| FLOAT \| DURATION` |=== - -*Considerations:* +.Considerations |=== | Any `null` values are excluded from the calculation. @@ -76,7 +59,7 @@ avg(expression) |=== -.+avg()+ +.+avg() - numerical values+ ====== .Query @@ -92,57 +75,15 @@ The average of all the values in the property `age` is returned: [role="queryresult",options="header,footer",cols="1*` |=== - -*Considerations:* - +.Considerations |=== | Any `null` values are ignored and will not be added to the list. @@ -224,8 +145,8 @@ All the values are collected and returned in a single list: [role="queryresult",options="header,footer",cols="1*` +|=== + +.Considerations +|=== +| `graph.names()` is only supported on link:{neo4j-docs-base-uri}/operations-manual/{page-version}/composite-databases[composite databases]. +|=== .+graph.names()+ ====== @@ -48,8 +58,20 @@ The names of all graphs on the current composite database are returned. [[functions-graph-propertiesByName]] == graph.propertiesByName() -Returns a map containing the properties associated with the given graph. The properties are set on the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/aliases/manage-aliases-standard-databases/[alias]that adds the graph as a constituent of a composite database. -It is only supported on link:{neo4j-docs-base-uri}/operations-manual/{page-version}/composite-databases[composite databases]. +.Details +|=== +| *Syntax* 3+| `graph.propertiesByName(graphName)` +| *Description* 3+| Returns the `MAP` of properties associated with a graph. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `graphName` | `STRING` | The name of the graph from which all associated properties will be returned. +| *Returns* 3+| `MAP` +|=== + +.Considerations +|=== +| `graph.propertiesByName()` is only supported on link:{neo4j-docs-base-uri}/operations-manual/{page-version}/composite-databases[composite databases]. +| The properties in the returned `MAP` are set on the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/aliases/manage-aliases-standard-databases/[alias]that adds the graph as a constituent of a composite database. +|=== .+graph.propertiesByName()+ ====== @@ -110,16 +132,20 @@ Returns all nodes from a subset of graphs that have a `tags` property containing [[functions-graph-byname]] == graph.byName() -Resolves a constituent graph by name. -It is only supported in the xref:clauses/use.adoc[`USE` clause], on link:{neo4j-docs-base-uri}/operations-manual/{page-version}/composite-databases[composite databases]. +.Details +|=== +| *Syntax* 3+| `graph.byName(name)` +| *Description* 3+| Returns the graph reference of the given name. It is only supported in the `USE` clause, on composite databases. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `name` | `STRING` | The name of the graph to be resolved. +| *Returns* 3+| `GRAPH` +|=== .+graph.byName()+ ====== .Query [source, cypher, indent=0] - -[source, cypher, role=noplay] ---- UNWIND graph.names() AS graphName CALL { @@ -138,8 +164,19 @@ Returns all nodes from all graphs on the current composite database. [[functions-graph-by-elementid]] == graph.byElementId() -The `graph.byElementId()` function is used in the xref:clauses/use.adoc[] clause to resolve a constituent graph to which a given element id belongs. -If the constituent database is not a standard database in the DBMS, an error will be thrown. +.Details +|=== +| *Syntax* 3+| `graph.byElementId(elementId)` +| *Description* 3+| Returns the graph reference with the given element id. It is only supported in the `USE` clause, on composite databases. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `elementId` | `STRING` | An element id of a node or relationship. +| *Returns* 3+| `GRAPH` +|=== + +.Considerations +|=== +| If the constituent database is not a standard database in the DBMS, an error will be thrown. +|=== .+graph.byElementId()+ ====== diff --git a/modules/ROOT/pages/functions/index.adoc b/modules/ROOT/pages/functions/index.adoc index 0e970cae0..315171f5c 100644 --- a/modules/ROOT/pages/functions/index.adoc +++ b/modules/ROOT/pages/functions/index.adoc @@ -3,213 +3,26 @@ [[query-function]] = Functions -This section contains information on all functions in the Cypher query language. - -* Predicate functions [xref::functions/index.adoc#header-query-functions-predicate[Summary]|xref::functions/predicate.adoc[Detail]] -* Scalar functions [xref::functions/index.adoc#header-query-functions-scalar[Summary]|xref::functions/scalar.adoc[Detail]] -* Aggregating functions [xref::functions/index.adoc#header-query-functions-aggregating[Summary]|xref::functions/aggregating.adoc[Detail]] -* List functions [xref::functions/index.adoc#header-query-functions-list[Summary]|xref::functions/list.adoc[Detail]] -* Mathematical functions - numeric [xref::functions/index.adoc#header-query-functions-numeric[Summary]|xref::functions/mathematical-numeric.adoc[Detail]] -* Mathematical functions - logarithmic [xref::functions/index.adoc#header-query-functions-logarithmic[Summary]|xref::functions/mathematical-logarithmic.adoc[Detail]] -* Mathematical functions - trigonometric [xref::functions/index.adoc#header-query-functions-trigonometric[Summary]|xref::functions/mathematical-trigonometric.adoc[Detail]] -* String functions [xref::functions/index.adoc#header-query-functions-string[Summary]|xref::functions/string.adoc[Detail]] -* Temporal functions - instant types [xref::functions/index.adoc#header-query-functions-temporal-instant-types[Summary]|xref::functions/temporal/index.adoc[Detail]] -* Temporal functions - duration [xref::functions/index.adoc#header-query-functions-temporal-duration[Summary]|xref::functions/temporal/duration.adoc[Detail]] -* Spatial functions [xref::functions/index.adoc#header-query-functions-spatial[Summary]|xref::functions/spatial.adoc[Detail]] -* Vector functions [xref::functions/index.adoc#header-query-functions-vector[Summary]|xref::functions/vector.adoc[Detail]] label:new[Introduced in 5.18] -* LOAD CSV functions [xref::functions/index.adoc#header-query-functions-load-csv[Summary]|xref::functions/load-csv.adoc[Detail]] -* Graph functions [xref::functions/index.adoc#header-query-functions-graph[Summary]|xref::functions/graph.adoc[Detail]] -* Database functions [xref::functions/index.adoc#header-query-functions-database[Summary]|xref::functions/database.adoc[Detail]] label:new[Introduced in 5.12] -* GenAI function [xref::functions/index.adoc#header-query-functions-genai[Summary]|xref::genai-integrations.adoc#single-embedding[Detail]] label:new[Introduced in 5.17] -* User-defined functions [xref::functions/index.adoc#header-query-functions-user-defined[Summary]|xref::functions/user-defined.adoc[Detail]] - -Related information may be found in xref::syntax/operators.adoc[Operators]. - -[NOTE] -==== -* Functions in Cypher return `null` if an input parameter is `null`. -* Functions taking a `STRING` as input all operate on _Unicode characters_ rather than on a standard `char[]`. - For example, the `size()` function applied to any _Unicode character_ will return `1`, even if the character does not fit in the 16 bits of one `char`. -==== +This section contains a summary of all functions in Cypher. +To list all functions, run the following query: -.List available functions -====== -To list the available functions, run the following xref::clauses/listing-functions.adoc[Cypher query]: - +.List all functions [source, cypher, indent=0] ---- SHOW FUNCTIONS ---- -====== - - -[[header-query-functions-predicate]] -**xref::functions/predicate.adoc[Predicate functions]** - -These functions return either true or false for the given arguments. - -[options="header"] -|=== -| Function | Signature | Description - -1.1+| xref::functions/predicate.adoc#functions-all[`all()`] -| `all(variable :: VARIABLE IN list :: LIST WHERE predicate :: ANY) :: BOOLEAN` -| Returns true if the predicate holds for all elements in the given `LIST`. - -1.1+| xref::functions/predicate.adoc#functions-any[`any()`] -| `any(variable :: VARIABLE IN list :: LIST WHERE predicate :: ANY) :: BOOLEAN` -| Returns true if the predicate holds for at least one element in the given `LIST`. - -1.1+| xref::functions/predicate.adoc#functions-exists[`exists()`] -| `exists(input :: ANY) :: BOOLEAN` -| Returns `true` if a match for the pattern exists in the graph. - -1.3+| xref::functions/predicate.adoc#functions-isempty[`isEmpty()`] -| `isEmpty(input :: LIST) :: BOOLEAN` -| Checks whether a `LIST` is empty. -| `isEmpty(input :: MAP) :: BOOLEAN` -| Checks whether a `MAP` is empty. -| `isEmpty(input :: STRING) :: BOOLEAN` -| Checks whether a `STRING` is empty. - -1.1+| xref::functions/predicate.adoc#functions-none[`none()`] -| `none(variable :: VARIABLE IN list :: LIST WHERE predicate :: ANY) :: BOOLEAN` -| Returns true if the predicate holds for no element in the given `LIST`. - -1.1+| xref::functions/predicate.adoc#functions-single[`single()`] -| `single(variable :: VARIABLE IN list :: LIST WHERE predicate :: ANY) :: BOOLEAN` -| Returns true if the predicate holds for exactly one of the elements in the given `LIST`. - -|=== - - -[[header-query-functions-scalar]] -**xref::functions/scalar.adoc[Scalar functions]** - -These functions return a single value. - -[options="header"] -|=== -| Function | Signature | Description - -1.1+| xref::functions/scalar.adoc#functions-char_length[`char_length()`] -| `char_length(input :: STRING) :: INTEGER` -| Returns the number of Unicode characters in a `STRING`. -label:new[Introduced in 5.13] - -1.1+| xref::functions/scalar.adoc#functions-character_length[`character_length()`] -| `character_length(input :: STRING) :: INTEGER` -| Returns the number of Unicode characters in a `STRING`. -label:new[Introduced in 5.13] -1.1+| xref::functions/scalar.adoc#functions-coalesce[`coalesce()`] -| `coalesce(input :: ANY) :: ANY` -| Returns the first non-null value in a list of expressions. - -1.2+| xref::functions/scalar.adoc#functions-elementid[`elementId()`] -| `elementId(input :: NODE) :: STRING` -| Returns a node identifier, unique within a specific transaction and DBMS. -| `elementId(input :: RELATIONSHIP) :: STRING` -| Returns a relationship identifier, unique within a specific transaction and DBMS. - -1.1+| xref::functions/scalar.adoc#functions-endnode[`endNode()`] -| `endNode(input :: RELATIONSHIP) :: NODE` -| Returns the end `NODE` of a `RELATIONSHIP`. - -1.1+| xref::functions/scalar.adoc#functions-head[`head()`] -| `head(list :: LIST) :: ANY` -| Returns the first element in a `LIST`. - -1.2+| xref::functions/scalar.adoc#functions-id[`id()`] -| `id(input :: NODE) :: INTEGER` -| label:deprecated[] Returns the id of a `NODE`. -Replaced by xref:functions/scalar.adoc#functions-elementid[`elementId()`]. -| `id(input :: RELATIONSHIP) :: INTEGER` -| label:deprecated[] Returns the id of a `RELATIONSHIP`. -Replaced by xref:functions/scalar.adoc#functions-elementid[`elementId()`]. - - -1.1+| xref::functions/scalar.adoc#functions-last[`last()`] -| `last(list :: LIST) :: ANY` -| Returns the last element in a `LIST`. - -1.1+| xref::functions/scalar.adoc#functions-length[`length()`] -| `length(input :: PATH) :: INTEGER` -| Returns the length of a `PATH`. - -1.1+| xref::functions/scalar.adoc#functions-nullIf[`nullIf()`] -| `nullIf(v1 :: ANY, v2 :: ANY) :: ANY` -| Returns null if the two given parameters are equivalent, otherwise returns the value of the first parameter. - -1.3+| xref::functions/scalar.adoc#functions-properties[`properties()`] -| `properties(input :: MAP) :: MAP` -| Returns a `MAP` containing all the properties of a `MAP`. -| `properties(input :: NODE) :: MAP` -| Returns a `MAP` containing all the properties of a `NODE`. -| `properties(input :: RELATIONSHIP) :: MAP` -| Returns a `MAP` containing all the properties of a `RELATIONSHIP`. - -1.1+| xref::functions/scalar.adoc#functions-randomuuid[`randomUUID()`] -| `randomUUID() :: STRING` -| Generates a random UUID. - -1.2+| xref::functions/scalar.adoc#functions-size[`size()`] -| `size(input :: LIST) :: INTEGER` -| Returns the number of items in a `LIST`. -| `size(input :: STRING) :: INTEGER` -| Returns the number of Unicode characters in a `STRING`. - -1.1+| xref::functions/scalar.adoc#functions-startnode[`startNode()`] -| `startNode(input :: RELATIONSHIP) :: NODE` -| Returns the start `NODE` of a `RELATIONSHIP`. - -1.3+| xref::functions/scalar.adoc#functions-toboolean[`toBoolean()`] -| `toBoolean(input :: STRING) :: BOOLEAN` -| Converts a `STRING` value to a `BOOLEAN` value. -| `toBoolean(input :: BOOLEAN) :: BOOLEAN` -| Converts a `BOOLEAN` value to a `BOOLEAN` value. -| `toBoolean(input :: INTEGER) :: BOOLEAN` -| Converts an `INTEGER` value to a `BOOLEAN` value. - -1.1+| xref::functions/scalar.adoc#functions-tobooleanornull[`toBooleanOrNull()`] -| `toBooleanOrNull(input :: ANY) :: BOOLEAN` -| Converts a value to a `BOOLEAN` value, or null if the value cannot be converted. - -1.2+| xref::functions/scalar.adoc#functions-tofloat[`toFloat()`] -| `toFloat(input :: INTEGER \| FLOAT) :: FLOAT` -| Converts an `INTEGER` value to a `FLOAT` value. -| `toFloat(input :: STRING) :: FLOAT` -| Converts a `STRING` value to a `FLOAT` value. - -1.1+| xref::functions/scalar.adoc#functions-tofloatornull[`toFloatOrNull()`] -| `toFloatOrNull(input :: ANY) :: FLOAT` -| Converts a value to a `FLOAT` value, or null if the value cannot be converted. - -1.3+| xref::functions/scalar.adoc#functions-tointeger[`toInteger()`] -| `toInteger(input :: INTEGER \| FLOAT) :: INTEGER` -| Converts a `FLOAT` value to an `INTEGER` value. -| `toInteger(input :: BOOLEAN) :: INTEGER` -| Converts a `BOOLEAN` value to an `INTEGER` value. -| `toInteger(input :: STRING) :: INTEGER` -| Converts a `STRING` value to an `INTEGER` value. -1.1+| xref::functions/scalar.adoc#functions-tointegerornull[`toIntegerOrNull()`] -| `toIntegerOrNull(input :: ANY) :: INTEGER` -| Converts a value to an `INTEGER` value, or null if the value cannot be converted. - -1.1+| xref::functions/scalar.adoc#functions-type[`type()`] -| `type(input :: RELATIONSHIP) :: STRING` -| Returns a `STRING` representation of the `RELATIONSHIP` type. - -1.1+| xref::functions/scalar.adoc#functions-valueType[`valueType()`] -| `valueType(input :: ANY) :: STRING` -| Returns a `STRING` representation of the most precise value type that the given expression evaluates to. - -|=== +For more information about this command, see xref::clauses/listing-functions.adoc[]. +[NOTE] +==== +Functions taking a `STRING` as input all operate on _Unicode characters_ rather than on a standard `char[]`. +For example, the `size()` function applied to any _Unicode character_ will return `1`, even if the character does not fit in the 16 bits of one `char`. +==== [[header-query-functions-aggregating]] -**xref::functions/aggregating.adoc[Aggregating functions]** +== Aggregating functions These functions take multiple values as arguments, and calculate and return an aggregated value from them. @@ -217,13 +30,9 @@ These functions take multiple values as arguments, and calculate and return an a |=== | Function | Signature | Description -1.3+| xref::functions/aggregating.adoc#functions-avg[`avg()`] -| `avg(input :: DURATION) :: DURATION` -| Returns the average of a set of `DURATION` values. -| `avg(input :: FLOAT) :: FLOAT` -| Returns the average of a set of `FLOAT` values. -| `avg(input :: INTEGER) :: INTEGER` -| Returns the average of a set of `INTEGER` values. +1.1+| xref::functions/aggregating.adoc#functions-avg[`avg()`] +| `avg(input :: INTEGER \| FLOAT \| DURATION) :: INTEGER \| FLOAT \| DURATION` +| Returns the average of a set of `INTEGER`, `FLOAT`, or `DURATION` values. 1.1+| xref::functions/aggregating.adoc#functions-collect[`collect()`] | `collect(input :: ANY) :: LIST` @@ -245,33 +54,71 @@ These functions take multiple values as arguments, and calculate and return an a | `percentileCont(input :: FLOAT, percentile :: FLOAT) :: FLOAT` | Returns the percentile of a value over a group using linear interpolation. -1.2+| xref::functions/aggregating.adoc#functions-percentiledisc[`percentileDisc()`] -| `percentileDisc(input :: FLOAT, percentile :: FLOAT) :: FLOAT` -| Returns the nearest `FLOAT` value to the given percentile over a group using a rounding method. -| `percentileDisc(input :: INTEGER, percentile :: FLOAT) :: INTEGER` -| Returns the nearest `INTEGER` value to the given percentile over a group using a rounding method. +1.1+| xref::functions/aggregating.adoc#functions-percentiledisc[`percentileDisc()`] +| `percentileDisc(input :: INTEGER \| FLOAT, percentile :: FLOAT) :: FLOAT` +| Returns the nearest `INTEGER` or `FLOAT` value to the given percentile over a group using a rounding method. -1.1+| xref::functions/aggregating.adoc#functions-stdev[`stdev()`] -| `stdev(input :: FLOAT) :: FLOAT` +1.1+| xref::functions/aggregating.adoc#functions-stdev[`stDev()`] +| `stDev(input :: FLOAT) :: FLOAT` | Returns the standard deviation for the given value over a group for a sample of a population. -1.1+| xref::functions/aggregating.adoc#functions-stdevp[`stdevp()`] -| `stdevp(input :: FLOAT) :: FLOAT` +1.1+| xref::functions/aggregating.adoc#functions-stdevp[`stDevP()`] +| `stDevP(input :: FLOAT) :: FLOAT` | Returns the standard deviation for the given value over a group for an entire population. -1.3+| xref::functions/aggregating.adoc#functions-sum[`sum()`] -| `sum(input :: DURATION) :: DURATION` -| Returns the sum of a set of `DURATION` values. -| `sum(input :: FLOAT) :: FLOAT` -| Returns the sum of a set of `FLOAT` values. -| `sum(input :: INTEGER) :: INTEGER` -| Returns the sum of a set of `INTEGER` values. +1.1+| xref::functions/aggregating.adoc#functions-sum[`sum()`] +| `sum(input :: INTEGER \| FLOAT \| DURATION) :: INTEGER \| FLOAT \| DURATION` +| Returns the sum of a set of `INTEGER`, `FLOAT`, or `DURATION` values. + |=== +[role=label--new-5.12] +[[header-query-functions-database]] +== Database functions + +Database functions provide information about databases. + +[options="header"] +|=== +| Function | Signature | Description +1.1+| xref:functions/database.adoc#functions-database-nameFromElementId[`db.nameFromElementId()`] +| `db.nameFromElementId(elementId :: STRING) :: STRING` +| Resolves the database name from the given element id. +|=== + + +[role=label--new-5.12] +[[header-query-functions-genai]] +== GenAI functions + +[options="header"] +|=== +| Function | Signature | Description +1.1+| xref:genai-integrations.adoc#single-embedding[`genai.vector.encode()`] | `genai.vector.encode(resource :: STRING, provider :: STRING, configuration :: MAP = {}) :: LIST` | Encode a given resource as a vector using the named provider. +|=== + + +[[header-query-functions-graph]] +== Graph functions + +Graph functions provide information about the constituent graphs in composite databases. + +[options="header"] +|=== +| Function | Signature | Description +1.1+| xref:functions/graph.adoc#functions-graph-by-elementid[`graph.byElementId()`] +| `USE graph.byElementId(elementId :: STRING)` +| Resolves the constituent graph to which a given element id belongs. +label:new[Introduced in 5.13] +1.1+| xref:functions/graph.adoc#functions-graph-byname[`graph.byName()`] | `USE graph.byName(name :: STRING)` | Resolves a constituent graph by name. +1.1+| xref:functions/graph.adoc#functions-graph-names[`graph.names()`] | `graph.names() :: LIST` | Returns a list containing the names of all graphs in the current composite database. +1.1+| xref:functions/graph.adoc#functions-graph-names[`graph.propertiesByName()`] | `graph.propertiesByName(name :: STRING) :: MAP` | Returns a map containing the properties associated with the given graph. +|=== + [[header-query-functions-list]] -**xref::functions/list.adoc[List functions]** +== List functions These functions return lists of other values. Further details and examples of lists may be found in xref::values-and-types/lists.adoc[Lists]. @@ -281,13 +128,9 @@ Further details and examples of lists may be found in xref::values-and-types/lis | Function | Signature | Description -1.3+| xref::functions/list.adoc#functions-keys[`keys()`] -| `keys(input :: MAP) :: LIST` -| Returns a `LIST` containing the `STRING` representations for all the property names of a `MAP`. -| `keys(input :: NODE) :: LIST` -| Returns a `LIST` containing the `STRING` representations for all the property names of a `NODE`. -| `keys(input :: RELATIONSHIP) :: LIST` -| Returns a `LIST` containing the `STRING` representations for all the property names of a `RELATIONSHIP`. +1.1+| xref::functions/list.adoc#functions-keys[`keys()`] +| `keys(input :: NODE \| RELATIONSHIP \| MAP) :: LIST` +| Returns a `LIST` containing the `STRING` representations for all the property names of a `MAP`, `NODE`, or `RELATIONSHIP`. 1.1+| xref::functions/list.adoc#functions-labels[`labels()`] | `labels(input :: NODE) :: LIST` @@ -297,14 +140,12 @@ Further details and examples of lists may be found in xref::values-and-types/lis | `nodes(input :: PATH) :: LIST` | Returns a `LIST` containing all the `NODE` values in a `PATH`. -1.2+| xref::functions/list.adoc#functions-range[`range()`] -| `range(start :: INTEGER, end :: INTEGER) :: LIST` -| Returns a `LIST` comprising all `INTEGER` values within a specified range. -| `range(start :: INTEGER, end :: INTEGER, step :: INTEGER) :: LIST` -| Returns a `LIST` comprising all `INTEGER` values within a specified range created with step length. +1.1+| xref::functions/list.adoc#functions-range[`range()`] +| `range(start :: INTEGER, end :: INTEGER [, step :: INTEGER]) :: LIST` +| Returns a `LIST` comprising all `INTEGER` values within a specified range, optionally specifying a step length. 1.1+| xref::functions/list.adoc#functions-reduce[`reduce()`] -| `reduce(accumulator :: VARIABLE = initial :: ANY, variable :: VARIABLE IN list :: LIST \| expression :: ANY) :: ANY` +| `reduce(accumulator :: VARIABLE = initial :: ANY, variable :: VARIABLE IN list :: LIST expression :: ANY) :: ANY` | Runs an expression against individual elements of a `LIST`, storing the result of the expression in an accumulator. 1.1+| xref::functions/list.adoc#functions-relationships[`relationships()`] @@ -346,52 +187,22 @@ If any values are not convertible to `STRING` they will be null in the `LIST, predicate :: ANY) :: BOOLEAN` +| Returns true if the predicate holds for all elements in the given `LIST`. + +1.1+| xref::functions/predicate.adoc#functions-any[`any()`] +| `any(variable :: ANY, list :: LIST, predicate :: ANY) :: BOOLEAN` +| Returns true if the predicate holds for at least one element in the given `LIST`. + +1.1+| xref::functions/predicate.adoc#functions-exists[`exists()`] +| `exists(input :: ANY) :: BOOLEAN` +| Returns `true` if a match for the pattern exists in the graph. + +1.1+| xref::functions/predicate.adoc#functions-isempty[`isEmpty()`] +| `isEmpty(input :: LIST \| MAP \| STRING ) :: BOOLEAN` +| Checks whether the given `LIST`, `MAP`, or `STRING` is empty. + +1.1+| xref::functions/predicate.adoc#functions-none[`none()`] +| `none(variable :: ANY, list :: LIST, predicate :: ANY) :: BOOLEAN` +| Returns true if the predicate holds for no element in the given `LIST`. + +1.1+| xref::functions/predicate.adoc#functions-single[`single()`] +| `single(variable :: ANY, list :: LIST, predicate :: ANY) :: BOOLEAN` +| Returns true if the predicate holds for exactly one of the elements in the given `LIST`. + +|=== + + +[[header-query-functions-scalar]] +== Scalar functions + +These functions return a single value. + +[options="header"] +|=== +| Function | Signature | Description + +1.1+| xref::functions/scalar.adoc#functions-char_length[`char_length()`] +| `char_length(input :: STRING) :: INTEGER` +| Returns the number of Unicode characters in a `STRING`. +label:new[Introduced in 5.13] + +1.1+| xref::functions/scalar.adoc#functions-character_length[`character_length()`] +| `character_length(input :: STRING) :: INTEGER` +| Returns the number of Unicode characters in a `STRING`. +label:new[Introduced in 5.13] + +1.1+| xref::functions/scalar.adoc#functions-coalesce[`coalesce()`] +| `coalesce(input :: ANY) :: ANY` +| Returns the first non-null value in a list of expressions. + +1.+| xref::functions/scalar.adoc#functions-elementid[`elementId()`] +| `elementId(input :: NODE \| RELATIONSHIP) :: STRING` +| Returns a node or relationship identifier, unique within a specific transaction and DBMS. + +1.1+| xref::functions/scalar.adoc#functions-endnode[`endNode()`] +| `endNode(input :: RELATIONSHIP) :: NODE` +| Returns the end `NODE` of a `RELATIONSHIP`. + +1.1+| xref::functions/scalar.adoc#functions-head[`head()`] +| `head(list :: LIST) :: ANY` +| Returns the first element in a `LIST`. + +1.1+| xref::functions/scalar.adoc#functions-id[`id()`] +| `id(input :: NODE \| RELATIONSHIP) :: INTEGER` +| label:deprecated[] Returns the id of a `NODE` or a `RELATIONSHIP`. +Replaced by xref:functions/scalar.adoc#functions-elementid[`elementId()`]. + +1.1+| xref::functions/scalar.adoc#functions-last[`last()`] +| `last(list :: LIST) :: ANY` +| Returns the last element in a `LIST`. + +1.1+| xref::functions/scalar.adoc#functions-length[`length()`] +| `length(input :: PATH) :: INTEGER` +| Returns the length of a `PATH`. + +1.1+| xref::functions/scalar.adoc#functions-nullIf[`nullIf()`] +| `nullIf(v1 :: ANY, v2 :: ANY) :: ANY` +| Returns `null` if the two given parameters are equivalent, otherwise returns the value of the first parameter. + +1.1+| xref::functions/scalar.adoc#functions-properties[`properties()`] +| `properties(input :: NODE \| RELATIONSHIP \| MAP) :: MAP` +| Returns a `MAP` containing all the properties of a `NODE` or `RELATIONSHIP`. + +1.1+| xref::functions/scalar.adoc#functions-randomuuid[`randomUUID()`] +| `randomUUID() :: STRING` +| Generates a random UUID. + +1.1+| xref::functions/scalar.adoc#functions-size[`size()`] +| `size(input STRING \| LIST) :: INTEGER` +| Returns the number of items in a `LIST` or the number of Unicode characters in a `STRING`. + +1.1+| xref::functions/scalar.adoc#functions-startnode[`startNode()`] +| `startNode(input :: RELATIONSHIP) :: NODE` +| Returns the start `NODE` of a `RELATIONSHIP`. + +1.1+| xref::functions/scalar.adoc#functions-toboolean[`toBoolean()`] +| `toBoolean(input :: BOOLEAN \| STRING \| INTEGER) :: BOOLEAN` +| Converts a `BOOLEAN`, `STRING`, or an `INTEGER` value to a `BOOLEAN` value. + +1.1+| xref::functions/scalar.adoc#functions-tobooleanornull[`toBooleanOrNull()`] +| `toBooleanOrNull(input :: ANY) :: BOOLEAN` +| Converts a value to a `BOOLEAN` value, or null if the value cannot be converted. + +1.1+| xref::functions/scalar.adoc#functions-tofloat[`toFloat()`] +| `toFloat(input :: STRING \| INTEGER \| FLOAT) :: FLOAT` +| Converts a `STRING` or `INTEGER` value to a `FLOAT` value. + +1.1+| xref::functions/scalar.adoc#functions-tofloatornull[`toFloatOrNull()`] +| `toFloatOrNull(input :: ANY) :: FLOAT` +| Converts a value to a `FLOAT` value, or null if the value cannot be converted. + +1.1+| xref::functions/scalar.adoc#functions-tointeger[`toInteger()`] +| `toInteger(input :: BOOLEAN \| STRING \| INTEGER \| FLOAT) :: INTEGER` +| Converts a `BOOLEAN, `STRING`, or `FLOAT` value to an `INTEGER` value. + +1.1+| xref::functions/scalar.adoc#functions-tointegerornull[`toIntegerOrNull()`] +| `toIntegerOrNull(input :: ANY) :: INTEGER` +| Converts a value to an `INTEGER` value, or null if the value cannot be converted. + +1.1+| xref::functions/scalar.adoc#functions-type[`type()`] +| `type(input :: RELATIONSHIP) :: STRING` +| Returns a `STRING` representation of the `RELATIONSHIP` type. + +1.1+| xref::functions/scalar.adoc#functions-valueType[`valueType()`] +| `valueType(input :: ANY) :: STRING` +| Returns a `STRING` representation of the most precise value type that the given expression evaluates to. + +|=== + + [[header-query-functions-string]] -**xref::functions/string.adoc[String functions]** +== String functions These functions are used to manipulate `STRING` values or to create a `STRING` representation of another value. @@ -499,11 +489,9 @@ These functions are used to manipulate `STRING` values or to create a `STRING` r |=== | Function | Signature | Description -1.2+| xref::functions/string.adoc#functions-btrim[`btrim()`] -| `btrim(original :: STRING) :: STRING` -| Returns the given `STRING` with leading and trailing whitespace removed. label:new[Introduced in 5.20] -| `btrim(input :: STRING, trimCharacterString :: STRING) :: STRING` -| Returns the given `STRING` with leading and trailing `trimCharacterString` characters removed. label:new[Introduced in 5.20] +1.1+| xref::functions/string.adoc#functions-btrim[`btrim()`] +| `btrim(original :: STRING [, trimCharacterString :: STRING ]) :: STRING` +| Returns the given `STRING` with leading and trailing whitespace removed, optionally specifying a `trimCharacterString` value to remove. label:new[Introduced in 5.20] 1.1+| xref::functions/string.adoc#functions-left[`left()`] | `left(original :: STRING, length :: INTEGER) :: STRING` @@ -513,17 +501,13 @@ These functions are used to manipulate `STRING` values or to create a `STRING` r | `lower(input :: STRING) :: STRING` | Returns the given `STRING` in lowercase. This function is an alias to the xref:functions/string.adoc#functions-tolower[`toLower()`] function, and it was introduced as part of Cypher's xref:appendix/gql-conformance/index.adoc[]. label:new[Introduced in 5.21] -1.2+| xref::functions/string.adoc#functions-ltrim[`ltrim()`] -| `ltrim(input :: STRING) :: STRING` -| Returns the given `STRING` with leading whitespace removed. -| `ltrim(input :: STRING, trimCharacterString :: STRING) :: STRING` -| Returns the given `STRING` with leading `trimCharacterString` characters removed. label:new[Introduced in 5.20] +1.1+| xref::functions/string.adoc#functions-ltrim[`ltrim()`] +| `ltrim(input :: STRING [, trimCharacterString :: STRING]) :: STRING` +| Returns the given `STRING` with leading whitespace removed, optionally specifying a `trimCharacterString` to remove. -1.2+| xref::functions/string.adoc#functions-normalize[`normalize()`] -| `normalize(input :: STRING) :: STRING` -| Returns the given `STRING` normalized according to the normalization form `NFC`. label:new[Introduced in 5.17] -| `normalize(input :: STRING, normalForm = NFC :: [NFC, NFD, NFKC, NFKD]) :: STRING` -| Returns the given `STRING` normalized according to the specified normalization form. label:new[Introduced in 5.17] +1.1+| xref::functions/string.adoc#functions-normalize[`normalize()`] +| `normalize(input :: STRING [,normalForm = NFC :: [NFC, NFD, NFKC, NFKD]]) :: STRING` +| Normalizes a `STRING`, optionally specifying a normalization form. label:new[Introduced in 5.17] 1.1+| xref::functions/string.adoc#functions-replace[`replace()`] | `replace(original :: STRING, search :: STRING, replace :: STRING) :: STRING` @@ -537,22 +521,16 @@ These functions are used to manipulate `STRING` values or to create a `STRING` r | `right(original :: STRING, length :: INTEGER) :: STRING` | Returns a `STRING` containing the specified number of rightmost characters in the given `STRING`. -1.2+| xref::functions/string.adoc#functions-rtrim[`rtrim()`] -| `rtrim(input :: STRING) :: STRING` -| Returns the given `STRING` with trailing whitespace removed. -| `rtrim(input :: STRING, trimCharacterString :: STRING) :: STRING` -| Returns the given `STRING` with trailing `trimCharacterString` characters removed. label:new[Introduced in 5.20] +1.1+| xref::functions/string.adoc#functions-rtrim[`rtrim()`] +| `rtrim(input :: STRING [, trimCharacterString :: STRING]) :: STRING` +| Returns the given `STRING` with trailing whitespace removed, optionally specifying a `trimCharacterString` of characters to remove. -1.2+| xref::functions/string.adoc#functions-split[`split()`] -| `split(original :: STRING, splitDelimiter :: STRING) :: LIST` -| Returns a `LIST` resulting from the splitting of the given `STRING` around matches of the given delimiter. +1.1+| xref::functions/string.adoc#functions-split[`split()`] | `split(original :: STRING, splitDelimiters :: LIST) :: LIST` | Returns a `LIST` resulting from the splitting of the given `STRING` around matches of any of the given delimiters. -1.2+| xref::functions/string.adoc#functions-substring[`substring()`] -| `substring(original :: STRING, start :: INTEGER) :: STRING` -| Returns a substring of the given `STRING`, beginning with a 0-based index start. -| `substring(original :: STRING, start :: INTEGER, length :: INTEGER) :: STRING` +1.1+| xref::functions/string.adoc#functions-substring[`substring()`] +| `substring(original :: STRING, start :: INTEGER length :: INTEGER) :: STRING` | Returns a substring of a given `length` from the given `STRING`, beginning with a 0-based index start. 1.1+| xref::functions/string.adoc#functions-tolower[`toLower()`] @@ -571,20 +549,72 @@ These functions are used to manipulate `STRING` values or to create a `STRING` r | `toUpper(input :: STRING) :: STRING` | Returns the given `STRING` in uppercase. -1.2+| xref::functions/string.adoc#functions-trim[`trim()`] -| `trim(input :: STRING) :: STRING` -| Returns the given `STRING` with leading and trailing whitespace removed. -| `trim([[LEADING \| TRAILING \| BOTH] [trimCharacterString :: STRING] FROM] input :: STRING) :: STRING` -| Returns the given `STRING` with the leading and/or trailing `trimCharacterString` character removed. label:new[Introduced in 5.20] +1.1+| xref::functions/string.adoc#functions-trim[`trim()`] +| `trim(trimCharacterString :: STRING, trimSpecification :: STRING, input :: STRING) :: STRING` +| Returns the given `STRING` with the leading and/or trailing `trimCharacterString` character removed. 1.1+| xref::functions/string.adoc#functions-upper[`upper()`] | `upper(input :: STRING) :: STRING` | Returns the given `STRING` in uppercase. This function is an alias to the xref:functions/string.adoc#functions-toupper[`toUpper()`] function, and it was introduced as part of Cypher's xref:appendix/gql-conformance/index.adoc[]. label:new[Introduced in 5.21] |=== +[[header-query-functions-spatial]] +== Spatial functions + +These functions are used to specify 2D or 3D points in a geographic or cartesian Coordinate Reference System and to calculate the geodesic distance between two points. + +[options="header"] +|=== +| Function | Signature | Description + +1.1+| xref::functions/spatial.adoc#functions-point-cartesian-2d[`point()`] +| `point(input :: MAP) :: POINT` +| Returns a 2D or 3D point object, given two or respectively three coordinate values in the Cartesian coordinate system or WGS 84 geographic coordinate system. + +1.1+| xref::functions/spatial.adoc#functions-distance[`point.distance()`] +| `point.distance(from :: POINT, to :: POINT) :: FLOAT` +| Returns a `FLOAT` representing the geodesic distance between any two points in the same CRS. + +1.1+| xref::functions/spatial.adoc#functions-withinBBox[`point.withinBBox()`] +| `point.withinBBox(point :: POINT, lowerLeft :: POINT, upperRight :: POINT) :: BOOLEAN` +| Returns `true` if the provided point is within the bounding box defined by the two provided points, `lowerLeft` and `upperRight`. + +|=== + + +[[header-query-functions-temporal-duration]] +== Temporal duration functions + +`DURATION` values of the xref::values-and-types/temporal.adoc[temporal types] can be created manipulated using the following functions: + +[options="header"] +|=== +| Function | Signature | Description + +1.1+| xref::functions/temporal/duration.adoc#functions-duration[`duration()`] +| `duration(input :: ANY) :: DURATION` +| Constructs a `DURATION` value. + +1.1+| xref::functions/temporal/duration.adoc#functions-duration-between[`duration.between()`] +| `duration.between(from :: ANY, to :: ANY) :: DURATION` +| Computes the `DURATION` between the `from` instant (inclusive) and the `to` instant (exclusive) in logical units. + +1.1+| xref::functions/temporal/duration.adoc#functions-duration-indays[`duration.inDays()`] +| `duration.inDays(from :: ANY, to :: ANY) :: DURATION` +| Computes the `DURATION` between the `from` instant (inclusive) and the `to` instant (exclusive) in days. + +1.1+| xref::functions/temporal/duration.adoc#functions-duration-inmonths[`duration.inMonths()`] +| `duration.inMonths(from :: ANY, to :: ANY) :: DURATION` +| Computes the `DURATION` between the `from` instant (inclusive) and the `to` instant (exclusive) in months. + +1.1+| xref::functions/temporal/duration.adoc#functions-duration-inseconds[`duration.inSeconds()`] +| `duration.inSeconds(from :: ANY, to :: ANY) :: DURATION` +| Computes the `DURATION` between the `from` instant (inclusive) and the `to` instant (exclusive) in seconds. + +|=== [[header-query-functions-temporal-instant-types]] -**xref::functions/temporal/index.adoc[Temporal instant types functions]** +== Temporal instant types functions Values of the xref::values-and-types/temporal.adoc[temporal types] -- `DATE`, `ZONED TIME`, `LOCAL TIME`, `ZONED DATETIME`, and `LOCAL DATETIME` -- can be created manipulated using the following functions: @@ -703,76 +733,31 @@ Values of the xref::values-and-types/temporal.adoc[temporal types] -- `DATE`, `Z |=== -[[header-query-functions-temporal-duration]] -**xref::functions/temporal/duration.adoc[Temporal duration functions]** - -`DURATION` values of the xref::values-and-types/temporal.adoc[temporal types] can be created manipulated using the following functions: - -[options="header"] -|=== -| Function | Signature | Description - -1.1+| xref::functions/temporal/duration.adoc#functions-duration[`duration()`] -| `duration(input :: ANY) :: DURATION` -| Constructs a `DURATION` value. - -1.1+| xref::functions/temporal/duration.adoc#functions-duration-between[`duration.between()`] -| `duration.between(from :: ANY, to :: ANY) :: DURATION` -| Computes the `DURATION` between the `from` instant (inclusive) and the `to` instant (exclusive) in logical units. - -1.1+| xref::functions/temporal/duration.adoc#functions-duration-indays[`duration.inDays()`] -| `duration.inDays(from :: ANY, to :: ANY) :: DURATION` -| Computes the `DURATION` between the `from` instant (inclusive) and the `to` instant (exclusive) in days. - -1.1+| xref::functions/temporal/duration.adoc#functions-duration-inmonths[`duration.inMonths()`] -| `duration.inMonths(from :: ANY, to :: ANY) :: DURATION` -| Computes the `DURATION` between the `from` instant (inclusive) and the `to` instant (exclusive) in months. - -1.1+| xref::functions/temporal/duration.adoc#functions-duration-inseconds[`duration.inSeconds()`] -| `duration.inSeconds(from :: ANY, to :: ANY) :: DURATION` -| Computes the `DURATION` between the `from` instant (inclusive) and the `to` instant (exclusive) in seconds. - -|=== - - -[[header-query-functions-spatial]] -**xref::functions/spatial.adoc[Spatial functions]** +[[header-query-functions-user-defined]] +== User-defined functions -These functions are used to specify 2D or 3D points in a geographic or cartesian Coordinate Reference System and to calculate the geodesic distance between two points. +User-defined functions are written in Java, deployed into the database and are called in the same way as any other Cypher function. +There are two main types of functions that can be developed and used: [options="header"] |=== -| Function | Signature | Description - -1.1+| xref::functions/spatial.adoc#functions-distance[`point.distance()`] -| `point.distance(from :: POINT, to :: POINT) :: FLOAT` -| Returns a `FLOAT` representing the geodesic distance between any two points in the same CRS. - -1.1+| xref::functions/spatial.adoc#functions-point-cartesian-2d[`point()` - Cartesian 2D] -| `point(input :: MAP) :: POINT` -| Returns a 2D point object, given two coordinate values in the Cartesian coordinate system. - -1.1+| xref::functions/spatial.adoc#functions-point-cartesian-3d[`point()` - Cartesian 3D] -| `point(input :: MAP) :: POINT` -| Returns a 3D point object, given three coordinate values in the Cartesian coordinate system. - -1.1+| xref::functions/spatial.adoc#functions-point-wgs84-2d[`point()` - WGS 84 2D] -| `point(input :: MAP) :: POINT` -| Returns a 2D point object, given two coordinate values in the WGS 84 geographic coordinate system. +| Type | Description | Usage | Developing -1.1+| xref::functions/spatial.adoc#functions-point-wgs84-3d[`point()` - WGS 84 3D] -| `point(input :: MAP) :: POINT` -| Returns a 3D point object, given three coordinate values in the WGS 84 geographic coordinate system. +| Scalar +| For each row the function takes parameters and returns a result. +| xref::functions/user-defined.adoc#query-functions-udf[Using UDF] +| link:{neo4j-docs-base-uri}/java-reference/{page-version}/extending-neo4j/functions#extending-neo4j-functions[Extending Neo4j (UDF)] -1.1+| xref::functions/spatial.adoc#functions-withinBBox[`point.withinBBox()`] -| `point.withinBBox(point :: POINT, lowerLeft :: POINT, upperRight :: POINT) :: BOOLEAN` -| Returns `true` if the provided point is within the bounding box defined by the two provided points, `lowerLeft` and `upperRight`. +| Aggregating +| Consumes many rows and produces an aggregated result. +| xref::functions/user-defined.adoc#query-functions-user-defined-aggregation[Using aggregating UDF] +| link:{neo4j-docs-base-uri}/java-reference/{page-version}/extending-neo4j/aggregation-functions#extending-neo4j-aggregation-functions[Extending Neo4j (Aggregating UDF)] |=== - +[role=label--new-5.18] [[header-query-functions-vector]] -**xref::functions/vector.adoc[Vector functions]** label:new[Introduced in 5.18] +== Vector functions Vector functions allow you to compute the similarity scores of vector pairs. @@ -789,85 +774,3 @@ Vector functions allow you to compute the similarity scores of vector pairs. | Returns a `FLOAT` representing the similarity between the argument vectors based on their Euclidean distance. |=== - - -[[header-query-functions-load-csv]] -**xref::functions/load-csv.adoc[LOAD CSV functions]** - -LOAD CSV functions can be used to get information about the file that is processed by `LOAD CSV`. - -[options="header"] -|=== -| Function | Signature | Description - -1.1+| xref::functions/load-csv.adoc#functions-file[`file()`] -| `file() :: STRING` -| Returns the absolute path of the file that LOAD CSV is using. - -1.1+| xref::functions/load-csv.adoc#functions-linenumber[`linenumber()`] -| `linenumber() :: INTEGER` -| Returns the line number that LOAD CSV is currently using. - -|=== - - -[[header-query-functions-graph]] -**xref::functions/graph.adoc[Graph functions]** - -Graph functions provide information about the constituent graphs in composite databases. - -[options="header"] -|=== -| Function | Signature | Description -1.1+| xref:functions/graph.adoc#functions-graph-by-elementid[`graph.byElementId()`] | `USE graph.byElementId(elementId :: STRING)` | Resolves the constituent graph to which a given element id belongs. -label:new[Introduced in 5.13] -1.1+| xref:functions/graph.adoc#functions-graph-byname[`graph.byName()`] | `USE graph.byName(name :: STRING)` | Resolves a constituent graph by name. -1.1+| xref:functions/graph.adoc#functions-graph-names[`graph.names()`] | `graph.names() :: LIST` | Returns a list containing the names of all graphs in the current composite database. -1.1+| xref:functions/graph.adoc#functions-graph-names[`graph.propertiesByName()`] | `graph.propertiesByName(name :: STRING) :: MAP` | Returns a map containing the properties associated with the given graph. -|=== - -[[header-query-functions-database]] -**xref::functions/database.adoc[Database functions]** label:new[Introduced in 5.12] - -Database functions provide information about databases. - -[options="header"] -|=== -| Function | Signature | Description -1.1+| xref:functions/database.adoc#functions-database-nameFromElementId[`db.nameFromElementId()`] | `db.nameFromElementId(name :: STRING) :: STRING` | Resolves the database name from the given element id. -label:new[Introduced in 5.12] -|=== - -[[header-query-functions-genai]] -**xref::genai-integrations.adoc#single-embedding[GenAI function]** label:new[Introduced in 5.17] - -This function is used to generate a vector embedding for a single value. - -[options="header"] -|=== -| Function | Signature | Description -1.1+| xref:genai-integrations.adoc#single-embedding[`genai.vector.encode()`] | `genai.vector.encode(resource :: STRING, provider :: STRING, configuration :: MAP = {}) :: LIST` | Encode a given resource as a vector using the named provider. -|=== - -[[header-query-functions-user-defined]] -**xref::functions/user-defined.adoc[User-defined functions]** - -User-defined functions are written in Java, deployed into the database and are called in the same way as any other Cypher function. -There are two main types of functions that can be developed and used: - -[options="header"] -|=== -| Type | Description | Usage | Developing - -| Scalar -| For each row the function takes parameters and returns a result. -| xref::functions/user-defined.adoc#query-functions-udf[Using UDF] -| link:{neo4j-docs-base-uri}/java-reference/{page-version}/extending-neo4j/functions#extending-neo4j-functions[Extending Neo4j (UDF)] - -| Aggregating -| Consumes many rows and produces an aggregated result. -| xref::functions/user-defined.adoc#query-functions-user-defined-aggregation[Using aggregating UDF] -| link:{neo4j-docs-base-uri}/java-reference/{page-version}/extending-neo4j/aggregation-functions#extending-neo4j-aggregation-functions[Extending Neo4j (Aggregating UDF)] - -|=== - diff --git a/modules/ROOT/pages/functions/list.adoc b/modules/ROOT/pages/functions/list.adoc index b118c9d60..2c16b1298 100644 --- a/modules/ROOT/pages/functions/list.adoc +++ b/modules/ROOT/pages/functions/list.adoc @@ -1,4 +1,5 @@ :description: List functions return lists of things -- nodes in a path, and so on. +:table-caption!: [[query-functions-list]] = List functions @@ -33,36 +34,16 @@ CREATE [[functions-keys]] == keys() -`keys` returns a `LIST` containing the `STRING` representations for all the property names of a `NODE`, `RELATIONSHIP`, or `MAP`. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -keys(expression) ----- - -*Returns:* - -|=== - -| `LIST` - -|=== - -*Arguments:* - -[options="header"] +.Details |=== -| Name | Description - -| `expression` -| An expression that returns a `NODE`, `RELATIONSHIP`, or `MAP`. - +| *Syntax* 3+| `keys(input)` +| *Description* 3+| Returns a `LIST` containing the `STRING` representations for all the property names of a `NODE`, `RELATIONSHIP` or `MAP`. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `NODE \| RELATIONSHIP \| MAP` | A node or relationship from which the names of all properties will be returned. +| *Returns* 3+| `LIST` |=== -*Considerations:* - +.Considerations |=== | `keys(null)` returns `null`. @@ -86,8 +67,8 @@ A `LIST` containing the names of all the properties on the node bound to [role="queryresult",options="header,footer",cols="1*` containing the names of all the properties on the node bound to [[functions-labels]] == labels() -`labels` returns a `LIST` containing the string representations for all the labels of a `NODE`. - -[NOTE] -The order of the returned labels is not guanteed when using the `labels()` function. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -labels(node) ----- - -*Returns:* - +.Details |=== - -| `LIST` - +| *Syntax* 3+| `labels(input)` +| *Description* 3+| Returns a `LIST` containing the `STRING` representations for all the labels of a `NODE`. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `NODE` | A node whose labels will be returned. +| *Returns* 3+| `LIST` |=== -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `node` -| An expression that returns a single `NODE`. - -|=== - -*Considerations:* +.Considerations |=== | `labels(null)` returns `null`. +| The order of the returned labels is not guaranteed when using the `labels()` function. |=== @@ -154,8 +114,8 @@ A `LIST` containing all the labels of the node bound to `a` is returned. [role="queryresult",options="header,footer",cols="1*` containing all the labels of the node bound to `a` is returned. [[functions-nodes]] == nodes() -`nodes()` returns a `LIST` containing all the `NODE` values in a `PATH`. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -nodes(path) ----- - -*Returns:* - +.Details |=== - -| `LIST` - -|=== - -*Arguments:* - -[options="header"] +| *Syntax* 3+| `nodes(input)` +| *Description* 3+| Returns a `LIST` containing all the `NODE` values in a `PATH`. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `PATH` | A path whose nodes will be returned. +| *Returns* 3+| `LIST` |=== -| Name | Description - -| `path` -| An expression that returns a `PATH`. - -|=== - -*Considerations:* +.Considerations |=== | `nodes(null)` returns `null`. @@ -232,42 +172,23 @@ A `LIST` containing all the nodes in the path `p` is returned. [[functions-range]] == range() -`range()` returns a `LIST` comprising all `INTEGER` values within a range bounded by a `start` value and an `end` value, where the difference `step` between any two consecutive values is constant; i.e. an arithmetic progression. -To create ranges with decreasing `INTEGER` values, use a negative value `step`. -The range is inclusive for non-empty ranges, and the arithmetic progression will therefore always contain `start` and -- depending on the values of `start`, `step` and `end` -- `end`. -The only exception where the range does not contain `start` are empty ranges. -An empty range will be returned if the value `step` is negative and `start - end` is positive, or vice versa, e.g. `range(0, 5, -1)`. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -range(start, end [, step]) ----- - -*Returns:* - +.Details |=== - -| `LIST` - +| *Syntax* 3+| `range(start, end [, step])` +| *Description* 3+| Returns a `LIST` comprising all `INTEGER` values within a specified range created with step length, optionally specifying a step length. +.4+| *Arguments* | *Name* | *Type* | *Description* +| `start` | `INTEGER` | The start value of the range. +| `end` | `INTEGER` | The end value of the range. +| `step` | `INTEGER` | The size of the increment (default value: 1). +| *Returns* 3+| `LIST` |=== -*Arguments:* - -[options="header"] +.Considerations |=== -| Name | Description - -| `start` -| An expression that returns an `INTEGER` value. - -| `end` -| An expression that returns an `INTEGER` value. - -| `step` -| A numeric expression defining the difference between any two consecutive values, with a default of `1`. - +| To create ranges with decreasing `INTEGER` values, use a negative value `step`. +| The range is inclusive for non-empty ranges, and the arithmetic progression will therefore always contain `start` and -- depending on the values of `start`, `step` and `end` -- `end`. +The only exception where the range does not contain `start` are empty ranges. +| An empty range will be returned if the value `step` is negative and `start - end` is positive, or vice versa, e.g. `range(0, 5, -1)`. |=== @@ -286,8 +207,8 @@ Three lists of numbers in the given ranges are returned. [role="queryresult",options="header,footer",cols="3*`, storing the result of the expression in an accumulator. +.3+| *Arguments* | *Name* | *Type* | *Description* +| `accumulator` | `ANY` | A variable that holds the result as the list is iterated. +| `variable` | `LIST` | A variable that can be used within the reducing expression. +| *Returns* 3+| `ANY` |=== -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `accumulator` -| A variable that will hold the result and the partial results as the list is iterated. - -| `initial` -| An expression that runs once to give a starting value to the accumulator. - -| `list` -| An expression that returns a `LIST`. - -| `variable` -| The closure will have a variable introduced in its context. We decide here which variable to use. - -| `expression` -| This expression will run once per value in the list, and produce the result value. - -|=== +This function is analogous to the `fold` or `reduce` method in functional languages such as Lisp and Scala. .+reduce()+ @@ -358,8 +249,8 @@ The `age` property of all `NODE` values in the `PATH` are summed and returned as [role="queryresult",options="header,footer",cols="1*` containing all the `RELATIONSHIP` values in a `PATH`.. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -relationships(path) ----- - -*Returns:* - +.Details |=== - -| `LIST` - +| *Syntax* 3+| `relationships(input)` +| *Description* 3+| Returns a `LIST` containing all the `RELATIONSHIP` values in a `PATH`. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `PATH` | The path from which all relationships will be returned. +| *Returns* 3+| `LIST` |=== -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `path` -| An expression that returns a `PATH`. - -|=== - -*Considerations:* - +.Considerations |=== | `relationships(null)` returns `null`. @@ -436,38 +307,20 @@ A `LIST` containing all the `RELATIONSHIP` values in the `PATH` `p [[functions-reverse-list]] == reverse() -`reverse()` returns a `LIST` in which the order of all elements in the given `LIST` have been reversed. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -reverse(original) ----- - -*Returns:* - +.Details |=== - -| A `LIST` containing homogeneous or heterogeneous elements; the types of the elements are determined by the elements within `original`. - -|=== - -*Arguments:* -[options="header"] -|=== -| Name | Description - -| `original` -| An expression that returns a `LIST`. - +| *Syntax* 3+| `reverse(input)` +| *Description* 3+| Returns a `STRING` or `LIST` in which the order of all characters or elements in the given `STRING` or `LIST` have been reversed. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `STRING \| LIST` | The string or list to be reversed. +| *Returns* 3+| `STRING \| LIST` |=== -*Considerations:* - +.Considerations |=== | Any `null` element in `original` is preserved. +| See also xref:functions/string.adoc#functions-reverse[String functions -> reverse]. |=== @@ -486,8 +339,8 @@ RETURN reverse(ids) [role="queryresult",options="header,footer",cols="1*,521,"abc",4923]+ +| reverse(ids) +| [487,,521,"abc",4923] 1+d|Rows: 1 |=== @@ -498,33 +351,14 @@ RETURN reverse(ids) [[functions-tail]] == tail() -`tail()` returns a `LIST` `l~result~` containing all the elements, excluding the first one, from a list `list`. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -tail(list) ----- - -*Returns:* - -|=== - -| A `LIST` containing heterogeneous elements; the types of the elements are determined by the elements in `list`. - +.Details |=== - -*Arguments:* -[options="header"] +| *Syntax* 3+| `tail(input)` +| *Description* 3+| Returns all but the first element in a `LIST`. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `LIST` | A list from which all but the first element will be returned. +| *Returns* 3+| `LIST` |=== -| Name | Description - -| `list` -| An expression that returns a `LIST`. - -|=== - .+tail()+ ====== @@ -542,8 +376,8 @@ The property named `array` and a `LIST` comprising all but the first elemen [role="queryresult",options="header,footer",cols="2*` comprising all but the first elemen [[functions-tobooleanlist]] == toBooleanList() -`toBooleanList()` converts a `LIST` and returns a `LIST`. -If any values are not convertible to `BOOLEAN` they will be `null` in the `LIST` returned. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -toBooleanList(list) ----- - -*Returns:* - +.Details |=== - -| A `LIST` containing the converted elements; depending on the input value a converted value is either a `BOOLEAN` value or `null`. - +| *Syntax* 3+| `toBooleanList(input)` +| *Description* 3+| Converts a `LIST` of values to a `LIST` values. If any values are not convertible to `BOOLEAN` they will be null in the `LIST` returned. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `LIST` | A list of values to be converted into a list of booleans. +| *Returns* 3+| `LIST` |=== -*Arguments:* -[options="header"] +.Considerations |=== -| Name | Description -| `list` -| An expression that returns a `LIST`. - -|=== - -*Considerations:* - -|=== - -| Any `null` element in `list` is preserved. -| Any `BOOLEAN` value in `list` is preserved. -| If the `list` is `null`, `null` will be returned. -| If the `list` is not a `LIST`, an error will be returned. +| Any `null` element in `input` is preserved. +| Any `BOOLEAN` value in `input` is preserved. +| If the `input` is `null`, `null` will be returned. +| If the `input` is not a `LIST`, an error will be returned. | The conversion for each value in `list` is done according to the xref::functions/scalar.adoc#functions-tobooleanornull[`toBooleanOrNull()` function]. |=== @@ -610,8 +424,8 @@ toBooleanList(['a string', true, 'false', null, ['A','B']]) as mixedList [role="queryresult",options="header,footer",cols="3*+ | +[,]+ | +[,true,false,,]+ +| noList | nullsInList | mixedList +| | [,] | [,true,false,,] 3+d|Rows: 1 |=== @@ -622,43 +436,23 @@ toBooleanList(['a string', true, 'false', null, ['A','B']]) as mixedList [[functions-tofloatlist]] == toFloatList() -`toFloatList()` converts a `LIST` of values and returns a `LIST`. -If any values are not convertible to `FLOAT` they will be `null` in the `LIST` returned. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -toFloatList(list) ----- - -*Returns:* - -|=== - -| A `LIST` containing the converted elements; depending on the input value a converted value is either a `FLOAT` value or `null`. - -|=== - -*Arguments:* -[options="header"] +.Details |=== -| Name | Description - -| `list` -| An expression that returns a `LIST`. - +| *Syntax* 3+| `toFloatList(input)` +| *Description* 3+| Converts a `LIST` to a `LIST` values. If any values are not convertible to `FLOAT` they will be null in the `LIST` returned. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `LIST` | A list of values to be converted into a list of floats. +| *Returns* 3+| `LIST` |=== -*Considerations:* - +.Considerations |=== | Any `null` element in `list` is preserved. | Any `FLOAT` value in `list` is preserved. -| If the `list` is `null`, `null` will be returned. -| If the `list` is not a `LIST`, an error will be returned. -| The conversion for each value in `list` is done according to the xref::functions/scalar.adoc#functions-tofloatornull[`toFloatOrNull()` function]. +| If the `input` is `null`, `null` will be returned. +| If the `input` is not a `LIST`, an error will be returned. +| The conversion for each value in `input` is done according to the xref::functions/scalar.adoc#functions-tofloatornull[`toFloatOrNull()` function]. |=== @@ -678,8 +472,8 @@ toFloatList(['a string', 2.5, '3.14159', null, ['A','B']]) as mixedList [role="queryresult",options="header,footer",cols="3*+ | +[,]+ | +[,2.5,3.14159,,]+ +| noList | nullsInList | mixedList +| | [,] | [,2.5,3.14159,,] 3+d|Rows: 1 |=== @@ -690,42 +484,22 @@ toFloatList(['a string', 2.5, '3.14159', null, ['A','B']]) as mixedList [[functions-tointegerlist]] == toIntegerList() -`toIntegerList()` converts a `LIST` of values and returns a `LIST`. -If any values are not convertible to `INTEGER` they will be `null` in the `LIST` returned. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -toIntegerList(list) ----- - -*Returns:* - -|=== - -| A `LIST` containing the converted elements; depending on the input value a converted value is either an `INTEGER` value or `null`. - +.Details |=== - -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `list` -| An expression that returns a `LIST`. - +| *Syntax* 3+| `toIntegerList(input)` +| *Description* 3+| Converts a `LIST` to a `LIST` values. If any values are not convertible to `INTEGER` they will be null in the `LIST` returned. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `LIST` | A list of values to be converted into a list of integers. +| *Returns* 3+| `LIST` |=== -*Considerations:* +.Considerations |=== -| Any `null` element in `list` is preserved. -| Any `INTEGER` value in `list` is preserved. -| If the `list` is `null`, `null` will be returned. -| If the `list` is not a `LIST`, an error will be returned. +| Any `null` element in `input` is preserved. +| Any `INTEGER` value in `input` is preserved. +| If the `input` is `null`, `null` will be returned. +| If the `input` is not a `LIST`, an error will be returned. | The conversion for each value in `list` is done according to the xref::functions/scalar.adoc#functions-tointegerornull[`toIntegerOrNull()` function]. |=== @@ -746,8 +520,8 @@ toIntegerList(['a string', 2, '5', null, ['A','B']]) as mixedList [role="queryresult",options="header,footer",cols="3*+ | +[,]+ | +[,2,5,,]+ +| noList | nullsInList | mixedList +| | [,] | [,2,5,,] 3+d|Rows: 1 |=== @@ -758,37 +532,16 @@ toIntegerList(['a string', 2, '5', null, ['A','B']]) as mixedList [[functions-tostringlist]] == toStringList() -`toStringList()` converts a `LIST` of values and returns a `LIST`. -If any values are not convertible to `STRING` they will be `null` in the `LIST` returned. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -toStringList(list) ----- - -*Returns:* - +.Details |=== - -| A `LIST` containing the converted elements; depending on the input value a converted value is either a `STRING` value or `null`. - +| *Syntax* 3+| `toStringList(input)` +| *Description* 3+| Converts a `LIST` to a `LIST` values. If any values are not convertible to `STRING` they will be null in the `LIST` returned. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `LIST` | A list of values to be converted into a list of strings. +| *Returns* 3+| `LIST` |=== -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `list` -| An expression that returns a `LIST`. - -|=== - -*Considerations:* - +.Considerations |=== | Any `null` element in `list` is preserved. @@ -815,8 +568,8 @@ toStringList(['already a string', 2, date({year:1955, month:11, day:5}), null, [ [role="queryresult",options="header,footer",cols="3*+ | +[,]+ | +["already a string","2","1955-11-05",,]+ +| noList | nullsInList | mixedList +| | [,] | ["already a string","2","1955-11-05",,] 3+d|Rows: 1 |=== diff --git a/modules/ROOT/pages/functions/load-csv.adoc b/modules/ROOT/pages/functions/load-csv.adoc index bb651f179..53a99f265 100644 --- a/modules/ROOT/pages/functions/load-csv.adoc +++ b/modules/ROOT/pages/functions/load-csv.adoc @@ -1,9 +1,10 @@ :description: LOAD CSV functions can be used to get information about the file that is processed by `LOAD CSV`. +:table-caption!: [[query-functions-load-csv]] = LOAD CSV functions -LOAD CSV functions can be used to get information about the file that is processed by the `LOAD CSV` clause. +LOAD CSV functions can be used to get information about the file that is processed by the xref:clauses/load-csv.adoc[`LOAD CSV`] clause. [IMPORTANT] ==== @@ -15,25 +16,14 @@ In all other contexts they will always return `null`. [[functions-linenumber]] == linenumber() -`linenumber()` returns the line number that `LOAD CSV` is currently using. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -linenumber() ----- - -*Returns:* - +.Details |=== - -| `INTEGER` - +| *Syntax* 3+| `linenumber()` +| *Description* 3+| Returns the line number that LOAD CSV is currently using. +| *Returns* 3+| `INTEGER` |=== -*Considerations:* - +.Considerations |=== | `null` will be returned if this function is called without a `LOAD CSV` context. @@ -44,28 +34,16 @@ linenumber() [[functions-file]] == file() -`file()` returns the absolute path of the file that `LOAD CSV` is using. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -file() ----- - -*Returns:* - +.Details |=== - -| `STRING` - +| *Syntax* 3+| `file()` +| *Description* 3+| Returns the absolute path of the file that LOAD CSV is using. +| *Returns* 3+| `STRING` |=== -*Considerations:* - +.Considerations |=== | `null` will be returned if this function is called without a `LOAD CSV` context. |=== - diff --git a/modules/ROOT/pages/functions/mathematical-logarithmic.adoc b/modules/ROOT/pages/functions/mathematical-logarithmic.adoc index 964a0c1bd..8186d42cc 100644 --- a/modules/ROOT/pages/functions/mathematical-logarithmic.adoc +++ b/modules/ROOT/pages/functions/mathematical-logarithmic.adoc @@ -1,4 +1,5 @@ :description: Logarithmic functions operate on numeric expressions only, and will return an error if used on any other values. +:table-caption!: [[query-functions-logarithmic]] = Mathematical functions - logarithmic @@ -9,24 +10,13 @@ Logarithmic mathematical functions operate on numeric expressions only, and will [[functions-e]] == e() -`e()` returns the base of the natural logarithm, `e`. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -e() ----- - -*Returns:* - +.Details |=== - -| `FLOAT` - +| *Syntax* 3+| `e()` +| *Description* 3+| Returns the base of the natural logarithm, e. +| *Returns* 3+| `FLOAT` |=== - .+e()+ ====== @@ -54,36 +44,16 @@ The base of the natural logarithm, `e`, is returned. [[functions-exp]] == exp() -`exp()` returns `e^n^`, where `e` is the base of the natural logarithm, and `n` is the value of the argument expression. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -e(expression) ----- - -*Returns:* - -|=== - -| `FLOAT` - +.Details |=== - -*Arguments:* - -[options="header"] +| *Syntax* 3+| `exp(input)` +| *Description* 3+| Returns e^n, where e is the base of the natural logarithm, and n is the value of the argument expression. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `FLOAT` | A value to which the base of the natural logarithm, e, will be raised. +| *Returns* 3+| `FLOAT` |=== -| Name | Description - -| `expression` -| A numeric expression. - -|=== - -*Considerations:* +.Considerations |=== | `exp(null)` returns `null`. @@ -107,8 +77,8 @@ RETURN exp(2) [role="queryresult",options="header,footer",cols="1*> without precision. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -round(expression, precision) ----- - -*Returns:* -|=== - -| `FLOAT` - -|=== - -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `expression` -| A numeric expression to be rounded. - -| `precision` -| A numeric expression specifying precision. - -|=== - -*Considerations:* - -|=== - -| `round()` returns `null` if any of its input parameters are `null`. - -|=== - +=== round() with precision .+round() with precision+ ====== @@ -466,8 +349,8 @@ RETURN round(3.141592, 3) [role="queryresult",options="header,footer",cols="1* 1), then (`acos(expression)`) returns `NaN`. +| If (`input` < -1) or (`input` > 1), then (`acos(input)`) returns `NaN`. |=== @@ -59,8 +41,8 @@ The arccosine of `0.5` is returned. .Result [role="queryresult",options="header,footer",cols="1* 1), then (`asin(expression)`) returns `NaN`. +| If (`input` < -1) or (`input` > 1), then (`asin(input)`) returns `NaN`. |=== @@ -121,8 +84,8 @@ The arcsine of `0.5` is returned. .Result [role="queryresult",options="header,footer",cols="1*`. +.4+| *Arguments* | *Name* | *Type* | *Description* +| `variable` | `ANY` | A variable that can be used within the `WHERE` clause. +| `list` | `LIST` | A predicate must hold for all elements in this list for the function to return `true`. +| `predicate` | `ANY` | A predicate that is tested against all items in the given list. +| *Returns* 3+| `BOOLEAN` |=== -*Arguments:* - -[options="header"] +.Considerations |=== - -| Name | Description - -| `list` -a| -An expression that returns a list. -A single element cannot be explicitly passed as a literal in the cypher statement. -However, an implicit conversion will happen for single elements when passing node properties during cypher execution. - -| `variable` -| A variable that can be used from within the predicate. - -| `predicate` -| A predicate that is tested against all items in the list. - +| `null` is returned if the `list` is `null` or if the `predicate` evaluates to `null` for at least one element and does not evaluate to false for any other element. |=== - .+all()+ ====== @@ -114,46 +90,22 @@ image::predicate_function_example.svg[width="300",role="middle"] [[functions-any]] == any() -The function `any()` returns `true` if the predicate holds for at least one element in the given list. - -`null` is returned if the list is `null`, or if the predicate evaluates to `null` for at least one element and does not evaluate to `true` for any other element. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -any(variable IN list WHERE predicate) ----- - -*Returns:* - +.Details |=== - -| `BOOLEAN` - +| *Syntax* 3+| `any(variable IN list WHERE predicate)` +| *Description* 3+| Returns true if the predicate holds for at least one element in the given `LIST`. +.4+| *Arguments* | *Name* | *Type* | *Description* +| `variable` | `ANY` | A variable that can be used within the `WHERE` clause. +| `list` | `LIST` | A predicate must hold for all elements in this list for the function to return `true`. +| `predicate` | `ANY` | A predicate that is tested against all items in the given list. +| *Returns* 3+| `BOOLEAN` |=== -*Arguments:* - -[options="header"] +.Considerations |=== -| Name | Description - -| `list` -a| -An expression that returns a list. -A single element cannot be explicitly passed as a literal in the cypher statement. -However, an implicit conversion will happen for single elements when passing node properties during cypher execution. - -| `variable` -| A variable that can be used from within the predicate. - -| `predicate` -| A predicate that is tested against all items in the list. - +| `null` is returned if the `list` is `null` or if the `predicate` evaluates to `null` for at least one element and does not evaluate to false for any other element. |=== - .+any()+ ====== @@ -185,41 +137,24 @@ The query returns the `Person` nodes with the `nationality` property value `Amer [[functions-exists]] == exists() -The function `exists()` returns `true` if a match for the given pattern exists in the graph. - -`null` is returned if the input argument is `null`. - -[NOTE] -==== -To check if a property is not `null` use the xref::syntax/operators.adoc#cypher-comparison[`IS NOT NULL` predicate]. -==== - -*Syntax:* - -[source, syntax, role="noheader"] ----- -exists(pattern) ----- - -*Returns:* - +.Details |=== - -| `BOOLEAN` - +| *Syntax* 3+| `exists(input)` +| *Description* 3+| Returns true if a match for the pattern exists in the graph. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `ANY` | A pattern to verify the existence of. +| *Returns* 3+| `BOOLEAN` |=== -*Arguments:* - -[options="header"] +.Considerations |=== -| Name | Description - -| `pattern` -| A pattern. - +| `null` is returned if `input` is `null`. |=== +[NOTE] +==== +To check if a property is not `null` use the xref::syntax/operators.adoc#cypher-comparison[`IS NOT NULL` predicate]. +==== .+exists()+ ====== @@ -239,13 +174,13 @@ This query returns the `name` property of every `Person` node, along with a bool [role="queryresult",options="header,footer",cols="2*` is empty. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `STRING \| MAP \| LIST` | A value to be checked for emptiness. +| *Returns* 3+| `BOOLEAN` |=== - .+isEmpty(list)+ ====== @@ -319,34 +232,6 @@ This query returns every `Person` node in the graph with a set `nationality` pro ====== - -*Syntax:* - -[source, syntax, role="noheader"] ----- -isEmpty(map) ----- - -*Returns:* - -|=== - -| `BOOLEAN` - -|=== - -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `map` -| An expression that returns a map. - -|=== - - .+isEmpty(map)+ ====== @@ -368,32 +253,6 @@ Because the example graph contains no empty nodes, nothing is returned: ====== -*Syntax:* - -[source, syntax, role="noheader"] ----- -isEmpty(string) ----- - -*Returns:* -|=== - -| `BOOLEAN` - -|=== - -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `string` -| An expression that returns a `STRING`. - -|=== - - .+isEmpty(string)+ ====== @@ -411,8 +270,8 @@ The `name` property of each node that has an empty `STRING` `address` property i [role="queryresult",options="header,footer",cols="1*`. +.4+| *Arguments* | *Name* | *Type* | *Description* +| `variable` | `ANY` | A variable that can be used within the `WHERE` clause. +| `list` | `LIST` | A predicate must hold for all elements in this list for the function to return `true`. +| `predicate` | `ANY` | A predicate that is tested against all items in the given list. +| *Returns* 3+| `BOOLEAN` |=== -*Arguments:* - -[options="header"] +.Considerations |=== -| Name | Description - -| `list` -a| -An expression that returns a list. -A single element cannot be explicitly passed as a literal in the cypher statement. -However, an implicit conversion will happen for single elements when passing node properties during cypher execution. - -| `variable` -| A variable that can be used from within the predicate. - -| `predicate` -| A predicate that is tested against all items in the list. - +| `null` is returned if the `list` is `null`, or if the `predicate` evaluates to `null` for at least one element and does not evaluate to `true` for any other element. |=== - .+none()+ ====== @@ -492,9 +328,9 @@ image::predicate_function_example.svg[width="300",role="middle"] [role="queryresult",options="header,footer",cols="1*(:Person {nationality: "American",name: "Carrie Anne Moss",age: 55})+ -| +(:Person {nationality: "Canadian",name: "Keanu Reeves",age: 58})-[:KNOWS]->(:Person {nationality: "American",name: "Carrie Anne Moss",age: 55})-[:KNOWS]->(:Person {nationality: "Australian",name: "Guy Pearce",age: 55})+ +| p +| (:Person {nationality: "Canadian",name: "Keanu Reeves",age: 58})-[:KNOWS]->(:Person {nationality: "American",name: "Carrie Anne Moss",age: 55}) +| (:Person {nationality: "Canadian",name: "Keanu Reeves",age: 58})-[:KNOWS]->(:Person {nationality: "American",name: "Carrie Anne Moss",age: 55})-[:KNOWS]->(:Person {nationality: "Australian",name: "Guy Pearce",age: 55}) 1+d|Rows: 2 |=== @@ -505,41 +341,22 @@ image::predicate_function_example.svg[width="300",role="middle"] [[functions-single]] == single() -The function `single()` returns `true` if the predicate holds for exactly _one_ of the elements in the given list. - -`null` is returned if the list is `null`, or if the predicate evaluates to `null` for at least one element and `true` for max one element. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -single(variable IN list WHERE predicate) ----- - -*Returns:* +.Details |=== - -| `BOOLEAN` - +| *Syntax* 3+| `single(variable IN list WHERE predicate)` +| *Description* 3+| Returns true if the predicate holds for exactly one of the elements in the given `LIST`. +.4+| *Arguments* | *Name* | *Type* | *Description* +| `variable` | `ANY` | A variable that can be used within the `WHERE` clause. +| `list` | `LIST` | A predicate must hold for all elements in this list for the function to return `true`. +| `predicate` | `ANY` | A predicate that is tested against all items in the given list. +| *Returns* 3+| `BOOLEAN` |=== -*Arguments:* -[options="header"] +.Considerations |=== -| Name | Description - -| `list` -| An expression that returns a list. - -| `variable` -| A variable that can be used from within the predicate. - -| `predicate` -| A predicate that is tested against all items in the list. - +| `null` is returned if the `list` is `null`, or if the `predicate` evaluates to `null` for at least one element and does not evaluate to `true` for any other element. |=== - .+single()+ ====== @@ -553,14 +370,14 @@ WHERE RETURN p ---- -In every returned path there is exactly one node which the `nationality` property value `Northern Irish`: +In every returned path there is exactly one node which has the `nationality` property value `Northern Irish`: .Result [role="queryresult",options="header,footer",cols="1*(:Person {nationality: "Northern Irish",name: "Liam Neeson",age: 70})+ +| p +| (:Person {nationality: "Canadian",name: "Keanu Reeves",age: 58})-[:KNOWS]->(:Person {nationality: "Northern Irish",name: "Liam Neeson",age: 70}) 1+d|Rows: 1 |=== diff --git a/modules/ROOT/pages/functions/scalar.adoc b/modules/ROOT/pages/functions/scalar.adoc index cb90dd063..48f431be0 100644 --- a/modules/ROOT/pages/functions/scalar.adoc +++ b/modules/ROOT/pages/functions/scalar.adoc @@ -1,4 +1,5 @@ :description: Scalar functions return a single value. +:table-caption!: [[query-functions-scalar]] = Scalar functions @@ -38,37 +39,18 @@ CREATE [[functions-char_length]] == char_length() -The function `char_length()` returns the number of Unicode characters in a `STRING`. -This function is an alias of the xref::functions/scalar.adoc#functions-size[`size()`] function, and was introduced as part of Cypher's xref:appendix/gql-conformance/index.adoc[]. - - -*Syntax:* - -[source, syntax, role="noheader"] ----- -char_length(string) ----- - -*Returns:* - +.Details |=== - -| `INTEGER` - +| *Syntax* 3+| `char_length(input)` +| *Description* 3+| Returns the number of Unicode characters in a `STRING`. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `STRING` | A string value whose length in characters is to be calculated. +| *Returns* 3+| `INTEGER` |=== -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `string` -| An expression that returns a `STRING`. - -|=== +This function is an alias of the xref::functions/scalar.adoc#functions-size[`size()`] function, and was introduced as part of Cypher's xref:appendix/gql-conformance/index.adoc[]. -*Considerations:* +.Considerations |=== | `char_length(null)` returns `null`. @@ -89,8 +71,8 @@ RETURN char_length('Alice') [role="queryresult",options="header,footer",cols="1*`. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `list` | `LIST` | A list from which the first element will be returned. +| *Returns* 3+| `ANY` |=== -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `expression` -| An expression that returns a list. - -|=== - -*Considerations:* +.Considerations |=== | `head(null)` returns `null`. @@ -446,8 +330,8 @@ The first element in the list is returned. [role="queryresult",options="header,footer",cols="2*`. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `list` | `LIST` | A list from which the last element will be returned. +| *Returns* 3+| `ANY` |=== *Considerations:* @@ -615,8 +449,8 @@ The last element in the list is returned. [role="queryresult",options="header,footer",cols="2*` or the number of Unicode characters in a `STRING`. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `STRING \| LIST` | A value whose length is to be calculated. +| *Returns* 3+| `INTEGER` |=== -| Name | Description - -| `list` -| An expression that returns a list. -|=== - -*Considerations:* +.Considerations |=== | `size(null)` returns `null`. |=== - -.+size()+ +.+size()+ applied to lists ====== .Query @@ -966,8 +707,8 @@ RETURN size(['Alice', 'Bob']) [role="queryresult",options="header,footer",cols="1*`. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -size(pattern comprehension) ----- - -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `pattern comprehension` -| A pattern comprehension that returns a list. - -|=== - - -.+size()+ +.+size()+ applied to pattern comprehensions ====== .Query @@ -1017,8 +733,8 @@ RETURN size([p=(a)-->()-->() | p]) AS fof [role="queryresult",options="header,footer",cols="1*+ | +false+ +| toBoolean('true') | toBoolean('not a boolean') | toBoolean(0) +| true | | false 3+d|Rows: 1 |=== @@ -1284,43 +909,23 @@ RETURN toBoolean('true'), toBoolean('not a boolean'), toBoolean(0) [[functions-tobooleanornull]] == toBooleanOrNull() -The function `toBooleanOrNull()` converts a `STRING`, `INTEGER` or `BOOLEAN` value to a `BOOLEAN` value. For any other input value, `null` will be returned. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -toBooleanOrNull(expression) ----- - -*Returns:* - +.Details |=== - -| `BOOLEAN` or `null`. - +| *Syntax* 3+| `toBooleanOrNull(input)` +| *Description* 3+| Converts a value to a `BOOLEAN` value, or null if the value cannot be converted. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `ANY` | A value to be converted into a boolean or null. +| *Returns* 3+| `BOOLEAN` |=== -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `expression` -| Any expression that returns a value. - -|=== - -*Considerations:* - +.Considerations |=== | `toBooleanOrNull(null)` returns `null`. -| If `expression` is a `BOOLEAN` value, it will be returned unchanged. +| If `input` is a `BOOLEAN` value, it will be returned unchanged. | If the parsing fails, `null` will be returned. -| If `expression` is the `INTEGER` value `0`, `false` will be returned. For any other `INTEGER` value `true` will be returned. -| If the `expression` is not a `STRING`, `INTEGER` or `BOOLEAN` value, `null` will be returned. +| If `input` is the `INTEGER` value `0`, `false` will be returned. For any other `INTEGER` value `true` will be returned. +| If the `input` is not a `STRING`, `INTEGER` or `BOOLEAN` value, `null` will be returned. |=== @@ -1336,8 +941,8 @@ RETURN toBooleanOrNull('true'), toBooleanOrNull('not a boolean'), toBooleanOrNul .Result [role="queryresult",options="header,footer",cols="4*+ | +false+ | ++ +| toBooleanOrNull('true') | toBooleanOrNull('not a boolean') | toBooleanOrNull(0) | toBooleanOrNull(1.5) +| true | | false | 4+d|Rows: 1 |=== @@ -1347,39 +952,20 @@ RETURN toBooleanOrNull('true'), toBooleanOrNull('not a boolean'), toBooleanOrNul [[functions-tofloat]] == toFloat() -The function `toFloat()` converts an `INTEGER`, `FLOAT` or a `STRING` value to a `FLOAT`. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -toFloat(expression) ----- - -*Returns:* +.Details |=== - -| `FLOAT` - +| *Syntax* 3+| `toFloat(input)` +| *Description* 3+| Converts a `STRING`, `INTEGER` or `FLOAT` value to a `FLOAT` value. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `STRING \| INTEGER \| FLOAT` | A value to be converted into a float. +| *Returns* 3+| `FLOAT` |=== -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `expression` -| An expression that returns an `INTEGER`, `FLOAT` or a `STRING` value. - -|=== - -*Considerations:* - +.Considerations |=== | `toFloat(null)` returns `null`. -| If `expression` is a `FLOAT`, it will be returned unchanged. +| If `input` is a `FLOAT`, it will be returned unchanged. | If the parsing fails, `null` will be returned. | This function will return an error if provided with an expression that is not an `INTEGER`, `FLOAT` or a `STRING` value. @@ -1397,10 +983,9 @@ RETURN toFloat('11.5'), toFloat('not a number') .Result [role="queryresult",options="header,footer",cols="2*+ +| toFloat('11.5') | toFloat('not a number') +| 11.5 | 2+d|Rows: 1 |=== @@ -1410,46 +995,25 @@ RETURN toFloat('11.5'), toFloat('not a number') [[functions-tofloatornull]] == toFloatOrNull() -The function `toFloatOrNull()` converts an `INTEGER`, `FLOAT` or a `STRING` value to a `FLOAT`. -For any other input value, `null` will be returned. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -toFloatOrNull(expression) ----- - -*Returns:* +.Details |=== - -| `FLOAT` or `null`. - -|=== - -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `expression` -| Any expression that returns a value. - +| *Syntax* 3+| `toFloatOrNull(input)` +| *Description* 3+| Converts a value to a `FLOAT` value, or null if the value cannot be converted. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `ANY` | A value to be converted into a float or null. +| *Returns* 3+| `FLOAT` |=== -*Considerations:* - +.Considerations |=== |`toFloatOrNull(null)` returns `null`. -|If `expression` is a `FLOAT`, it will be returned unchanged. +|If `input` is a `FLOAT`, it will be returned unchanged. |If the parsing fails, `null` will be returned. -|If the `expression` is not an `INTEGER`, `FLOAT` or a `STRING` value, `null` will be returned. +|If the `input` is not an `INTEGER`, `FLOAT` or a `STRING` value, `null` will be returned. |=== - .+toFloatOrNull()+ ====== @@ -1463,8 +1027,8 @@ RETURN toFloatOrNull('11.5'), toFloatOrNull('not a number'), toFloatOrNull(true) [role="queryresult",options="header,footer",cols="3*+ | ++ +| toFloatOrNull('11.5') | toFloatOrNull('not a number') | toFloatOrNull(true) +| 11.5 | | 3+d|Rows: 1 |=== @@ -1475,43 +1039,23 @@ RETURN toFloatOrNull('11.5'), toFloatOrNull('not a number'), toFloatOrNull(true) [[functions-tointeger]] == toInteger() -The function `toInteger()` converts a `BOOLEAN`, `INTEGER`, `FLOAT` or a `STRING` value to an `INTEGER` value. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -toInteger(expression) ----- - -*Returns:* - -|=== - -| `INTEGER` - +.Details |=== - -*Arguments:* - -[options="header"] +| *Syntax* 3+| `toInteger(input)` +| *Description* 3+| Converts a `BOOLEAN`, `STRING`, `INTEGER` or `FLOAT` value to an `INTEGER` value. For `BOOLEAN` values, true is defined to be 1 and false is defined to be 0. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `BOOLEAN \| STRING \| INTEGER \| FLOAT` | A value to be converted into an integer. +| *Returns* 3+| `INTEGER` |=== -| Name | Description - -| `expression` -| An expression that returns a `BOOLEAN`, `FLOAT`, `INTEGER` or a `STRING` value. - -|=== - -*Considerations:* +.Considerations |=== | `toInteger(null)` returns `null`. -| If `expression` is an integer value, it will be returned unchanged. +| If `input` is an `INTEGER` value, it will be returned unchanged. | If the parsing fails, `null` will be returned. -| If `expression` is the boolean value `false`, `0` will be returned. -| If `expression` is the boolean value `true`, `1` will be returned. +| If `input` is the boolean value `false`, `0` will be returned. +| If `input` is the boolean value `true`, `1` will be returned. | This function will return an error if provided with an expression that is not a `BOOLEAN`, `FLOAT`, `INTEGER` or a `STRING` value. |=== @@ -1530,8 +1074,8 @@ RETURN toInteger('42'), toInteger('not a number'), toInteger(true) [role="queryresult",options="header,footer",cols="3*+ | +1+ +| toInteger('42') | toInteger('not a number') | toInteger(true) +| 42 | | 1 3+d|Rows: 1 |=== @@ -1542,42 +1086,24 @@ RETURN toInteger('42'), toInteger('not a number'), toInteger(true) [[functions-tointegerornull]] == toIntegerOrNull() -The function `toIntegerOrNull()` converts a `BOOLEAN`, `INTEGER`, `FLOAT` or a `STRING` value to an `INTEGER` value. For any other input value, `null` will be returned. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -toIntegerOrNull(expression) ----- - -*Returns:* -|=== - -| `INTEGER` or `null`. - +.Details |=== - -*Arguments:* - -[options="header"] +| *Syntax* 3+| `toIntegerOrNull(input)` +| *Description* 3+| Converts a value to an `INTEGER` value, or null if the value cannot be converted. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `ANY` | A value to be converted into an integer or null. +| *Returns* 3+| `INTEGER` |=== -| Name | Description - -| `expression` | Any expression that returns a value. - -|=== - -*Considerations:* +.Considerations |=== | `toIntegerOrNull(null)` returns `null`. -| If `expression` is an integer value, it will be returned unchanged. +| If `input` is an `INTEGER` value, it will be returned unchanged. | If the parsing fails, `null` will be returned. -| If `expression` is the `BOOLEAN` value `false`, `0` will be returned. -| If `expression` is the `BOOLEAN` value `true`, `1` will be returned. -| If the `expression` is not a `BOOLEAN`, `FLOAT`, `INTEGER` or a `STRING` value, `null` will be returned. +| If `input` is the `BOOLEAN` value `false`, `0` will be returned. +| If `input` is the `BOOLEAN` value `true`, `1` will be returned. +| If the `input` is not a `BOOLEAN`, `FLOAT`, `INTEGER` or a `STRING` value, `null` will be returned. |=== @@ -1595,8 +1121,8 @@ RETURN toIntegerOrNull('42'), toIntegerOrNull('not a number'), toIntegerOrNull(t [role="queryresult",options="header,footer",cols="4*+ | +1+ | ++ +| toIntegerOrNull('42') | toIntegerOrNull('not a number') | toIntegerOrNull(true) | toIntegerOrNull(['A', 'B', 'C']) +| 42 | | 1 | 4+d|Rows: 1 |=== @@ -1607,35 +1133,16 @@ RETURN toIntegerOrNull('42'), toIntegerOrNull('not a number'), toIntegerOrNull(t [[functions-type]] == type() -The function `type()` returns the `STRING` representation of the `RELATIONSHIP` type. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -type(relationship) ----- - -*Returns:* - +.Details |=== - -| `STRING` - -|=== - -*Arguments:* - -[options="header"] +| *Syntax* 3+| `type(input)` +| *Description* 3+| Returns a `STRING` representation of the `RELATIONSHIP` type. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `RELATIONSHIP` | A relationship. +| *Returns* 3+| `STRING` |=== -| Name | Description -| `relationship` -| An expression that returns a `RELATIONSHIP`. - -|=== - -*Considerations:* +.Considerations |=== @@ -1661,9 +1168,9 @@ The relationship type of `r` is returned. [role="queryresult",options="header,footer",cols="1* NOT NULL"+ +| result +| "STRING NOT NULL" +| "INTEGER NOT NULL" +| "FLOAT NOT NULL" +| "BOOLEAN NOT NULL" +| "LIST NOT NULL" 1+d|Rows: 5 |=== diff --git a/modules/ROOT/pages/functions/spatial.adoc b/modules/ROOT/pages/functions/spatial.adoc index 7243a0a72..5dc4d910d 100644 --- a/modules/ROOT/pages/functions/spatial.adoc +++ b/modules/ROOT/pages/functions/spatial.adoc @@ -1,4 +1,5 @@ :description: Spatial functions are used to specify 2D or 3D points in a Coordinate Reference System (CRS) and to calculate the geodesic distance between two points. +:table-caption!: [[query-functions-spatial]] = Spatial functions @@ -19,78 +20,76 @@ CREATE (copenhagen)-[:TRAVEL_ROUTE]->(malmo) ---- -[[functions-distance]] -== point.distance() - -`point.distance()` returns a `FLOAT` representing the geodesic distance between two points in the same Coordinate Reference System (CRS). - -* If the `POINT` values are in the _Cartesian_ CRS (2D or 3D), then the units of the returned distance will be the same as the units of the points, calculated using Pythagoras' theorem. -* If the `POINT` values are in the _WGS-84_ CRS (2D), then the units of the returned distance will be meters, based on the haversine formula over a spherical earth approximation. -* If the `POINT` values are in the _WGS-84_ CRS (3D), then the units of the returned distance will be meters. - ** The distance is calculated in two steps. - *** First, a haversine formula over a spherical earth is used, at the average height of the two points. - *** To account for the difference in height, Pythagoras' theorem is used, combining the previously calculated spherical distance with the height difference. - ** This formula works well for points close to the earth's surface; for instance, it is well-suited for calculating the distance of an airplane flight. -It is less suitable for greater heights, however, such as when calculating the distance between two satellites. - -[source, syntax] ----- -point.distance(point1, point2) ----- +[[functions-point]] +== point() -*Returns:* +.Details |=== +| *Syntax* 3+| `point(input)` +| *Description* 3+| Returns a 2D or 3D point object, given two or respectively three coordinate values in the Cartesian coordinate system or WGS 84 geographic coordinate system. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `MAP` | Cartesian 2D: `{ + +x :: FLOAT, + +y :: FLOAT, + +crs = "cartesian" :: STRING, + +srid = 7203 :: INTEGER + +}` -| `FLOAT` - -|=== +Cartesian 3D: `{ + +x :: FLOAT, + +y :: FLOAT, + +z :: FLOAT, + +crs = "cartesian-3D" :: STRING, + +srid = 9157 :: INTEGER + +}` -*Arguments:* +WGS 84 2D: `{ + +longitude \| x :: FLOAT + +latitude \| y :: FLOAT + +crs = "WGS-84-2D" :: STRING + +srid = 4326 :: INTEGER + +}` -[options="header"] +WGS 84 3D: `{ + +longitude \| x :: FLOAT, + +latitude \| y :: FLOAT, + +height \| z :: FLOAT, + +crs = "WGS-84-3D" :: STRING, + +srid = 4979 :: INTEGER + +}` +| *Returns* 3+| `POINT` |=== -| Name | Description - -| `point1` -| A `POINT` in either a geographic or cartesian coordinate system. - -| `point2` -| A `POINT` in the same CRS as `point1`. +.Considerations |=== -*Considerations:* -|=== - -| `point.distance(null, null)` return `null`. -| `point.distance(null, point2)` return `null`. -| `point.distance(point1, null)` return `null`. -| Attempting to use points with different Coordinate Reference Systems (such as WGS 84 2D and WGS 84 3D) will return `null`. +| If any argument provided to `point()` is `null`, `null` will be returned. +| If the coordinates are specified using `latitude` and `longitude`, the `crs` or `srid` fields are optional and inferred to be `'WGS-84'` (`srid:4326`) for 2D points or `'WGS-84-3D'` (`srid:4979`) for 3D points. +| If the coordinates are specified using `x` and `y`, then either the `crs` or `srid` field is required if a geographic CRS is desired. +| If the `height/z` key and value is not provided, a 2D `POINT` will be returned in either the _WGS 84_ or _Cartesian_ CRS, depending on the coordinate system used. +| The `crs` or `srid` fields are optional and default to the _Cartesian_ CRS (which means `srid:7203`) for 2D points or the _3D Cartesian_ CRS (which means `srid:9157`) for 3D points. |=== -.+point.distance()+ +.+point()+ - WGS 84 2D ====== .Query [source, cypher] ---- -WITH - point({x: 2.3, y: 4.5, crs: 'cartesian'}) AS p1, - point({x: 1.1, y: 5.4, crs: 'cartesian'}) AS p2 -RETURN point.distance(p1,p2) AS dist +RETURN point({longitude: 56.7, latitude: 12.78}) AS point ---- -The distance between two 2D points in the _Cartesian_ CRS is returned. +A 2D `POINT` with a `longitude` of `56.7` and a `latitude` of `12.78` in the _WGS 84_ CRS is returned. .Result [role="queryresult",options="header,footer",cols="1*(o:Office) -WITH - point({longitude: t.longitude, latitude: t.latitude}) AS trainPoint, - point({longitude: o.longitude, latitude: o.latitude}) AS officePoint -RETURN round(point.distance(trainPoint, officePoint)) AS travelDistance +MATCH (p:Office) +RETURN point({longitude: p.longitude, latitude: p.latitude}) AS officePoint ---- -The distance between the train station in Copenhagen and the Neo4j office in Malmo is returned. +A 2D `POINT` representing the coordinates of the city of Malmo in the _WGS 84_ CRS is returned. .Result [role="queryresult",options="header,footer",cols="1*+ -1+d|Rows: 1 - -|=== - -====== - - -[[functions-withinBBox]] -== point.withinBBox() - -`point.withinBBox()` takes the following arguments: - -* The `POINT` to check. -* The lower-left (south-west) `POINT` of a bounding box. -* The upper-right (or north-east) `POINT` of a bounding box. - -The return value will be true if the provided point is contained in the bounding box (boundary included), otherwise the return value will be false. - -[source, syntax] ----- -point.withinBBox(point, lowerLeft, upperRight) ----- - -*Returns:* - -|=== - -| `BOOLEAN` - -|=== - -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `point` -| A `POINT` in either a geographic or cartesian coordinate system. - -| `lowerLeft` -| A `POINT` in the same CRS as 'point'. - -| `upperRight` -| A `POINT` in the same CRS as 'point'. - -|=== - -*Considerations:* - -|=== - -| `point.withinBBox(p1, p2, p3)` will return `null` if any of the arguments evaluate to `null`. -| Attempting to use `POINT` values with different Coordinate Reference Systems (such as WGS 84 2D and WGS 84 3D) will return `null`. -| `point.withinBBox` will handle crossing the 180th meridian in geographic coordinates. -| Switching the longitude of the `lowerLeft` and `upperRight` in geographic coordinates will switch the direction of the resulting bounding box. -| Switching the latitude of the `lowerLeft` and `upperRight` in geographic coordinates so that the former is north of the latter will result in an empty range. - -|=== - - -.+point.withinBBox()+ -====== - -.Query -[source, cypher] ----- -WITH - point({x: 0, y: 0, crs: 'cartesian'}) AS lowerLeft, - point({x: 10, y: 10, crs: 'cartesian'}) AS upperRight -RETURN point.withinBBox(point({x: 5, y: 5, crs: 'cartesian'}), lowerLeft, upperRight) AS result +RETURN point({longitude: 56.7, latitude: 12.78, height: 8}) AS point ---- -Checking if a point in _Cartesian_ CRS is contained in the bounding box. +A 3D `POINT` with a `longitude` of `56.7`, a `latitude` of `12.78` and a height of `8` meters in the _WGS 84_ CRS is returned. .Result [role="queryresult",options="header,footer",cols="1*+ 1+d|Rows: 1 @@ -343,75 +241,59 @@ If `null` is provided as any of the arguments, `null` is returned. ====== -[[functions-point-wgs84-2d]] -== point() - WGS 84 2D - -`point({longitude | x, latitude | y [, crs][, srid]})` returns a 2D `POINT` in the _WGS 84_ CRS corresponding to the given coordinate values. - -[source, syntax] ----- -point({longitude | x, latitude | y [, crs][, srid]}) ----- - -*Returns:* - -|=== - -| A 2D `POINT` in _WGS 84_. +[[functions-distance]] +== point.distance() +.Details |=== - -*Arguments:* - -[options="header"] +| *Syntax* 3+| `point.distance(from, to)` +| *Description* 3+| Returns a `FLOAT` representing the geodesic distance between any two points in the same CRS. +.3+| *Arguments* | *Name* | *Type* | *Description* +| `from` | `POINT` | A start point. +| `to` | `POINT` | An end point in the same CRS as the start point. +| *Returns* 3+| `FLOAT` |=== -| Name | Description - -| `A single map consisting of the following:` -| - -| `longitude/x` -| A numeric expression that represents the longitude/x value in decimal degrees. - -| `latitude/y` -| A numeric expression that represents the latitude/y value in decimal degrees. - -| `crs` -| The optional `STRING` `'WGS-84'`. - -| `srid` -| The optional `INTEGER` `4326`. -|=== - -*Considerations:* +* If the `POINT` values are in the _Cartesian_ CRS (2D or 3D), then the units of the returned distance will be the same as the units of the points, calculated using Pythagoras' theorem. +* If the `POINT` values are in the _WGS-84_ CRS (2D), then the units of the returned distance will be meters, based on the haversine formula over a spherical Earth approximation. +* If the `POINT` values are in the _WGS-84_ CRS (3D), then the units of the returned distance will be meters. + ** The distance is calculated in two steps. + *** First, a haversine formula over a spherical Earth is used, at the average height of the two points. + *** To account for the difference in height, Pythagoras' theorem is used, combining the previously calculated spherical distance with the height difference. + ** This formula works well for points close to the earth's surface; for instance, it is well-suited for calculating the distance of an airplane flight. +It is less suitable for greater heights, however, such as when calculating the distance between two satellites. +.Considerations |=== -| If any argument provided to `point()` is `null`, `null` will be returned. -| If the coordinates are specified using `latitude` and `longitude`, the `crs` or `srid` fields are optional and inferred to be `'WGS-84'` (`srid:4326`). -| If the coordinates are specified using `x` and `y`, then either the `crs` or `srid` field is required if a geographic CRS is desired. +| `point.distance(null, null)` return `null`. +| `point.distance(null, to)` return `null`. +| `point.distance(from, null)` return `null`. +| Attempting to use points with different Coordinate Reference Systems (such as WGS 84 2D and WGS 84 3D) will return `null`. |=== -.+point()+ +.+point.distance()+ ====== .Query [source, cypher] ---- -RETURN point({longitude: 56.7, latitude: 12.78}) AS point +WITH + point({x: 2.3, y: 4.5, crs: 'cartesian'}) AS p1, + point({x: 1.1, y: 5.4, crs: 'cartesian'}) AS p2 +RETURN point.distance(p1,p2) AS dist ---- -A 2D `POINT` with a `longitude` of `56.7` and a `latitude` of `12.78` in the _WGS 84_ CRS is returned. +The distance between two 2D points in the _Cartesian_ CRS is returned. .Result [role="queryresult",options="header,footer",cols="1*(o:Office) +WITH + point({longitude: t.longitude, latitude: t.latitude}) AS trainPoint, + point({longitude: o.longitude, latitude: o.latitude}) AS officePoint +RETURN round(point.distance(trainPoint, officePoint)) AS travelDistance ---- -A 2D `POINT` representing the coordinates of the city of Malmo in the _WGS 84_ CRS is returned. +The distance between the train station in Copenhagen and the Neo4j office in Malmo is returned. .Result [role="queryresult",options="header,footer",cols="1*+ +| d +| null 1+d|Rows: 1 |=== @@ -492,79 +380,52 @@ If `null` is provided as the argument, `null` is returned. ====== -[[functions-point-wgs84-3d]] -== point() - WGS 84 3D - -`point({longitude | x, latitude | y, height | z, [, crs][, srid]})` returns a 3D `POINT` in the _WGS 84_ CRS corresponding to the given coordinate values. - -[source, syntax] ----- -point({longitude | x, latitude | y, height | z, [, crs][, srid]}) ----- - -*Returns:* +[[functions-withinBBox]] +== point.withinBBox() +.Details |=== - -| A 3D `POINT` in _WGS 84_. - +| *Syntax* 3+| `point.withinBBox(point, lowerLeft, upperRight)` +| *Description* 3+| Returns true if the provided point is within the bounding box defined by the two provided points. +.4+| *Arguments* | *Name* | *Type* | *Description* +| `point` | `POINT` | A point to be confirmed in the bounding box. +| `lowerLeft` | `POINT` | The lower left side point of the bounding box. +| `upperRight` | `POINT` | The upper right side point of the bounding box. +| *Returns* 3+| `BOOLEAN` |=== -*Arguments:* - -[options="header"] +.Considerations |=== -| Name | Description - -| `A single map consisting of the following:` -| - -| `longitude/x` -| A numeric expression that represents the longitude/x value in decimal degrees. - -| `latitude/y` -| A numeric expression that represents the latitude/y value in decimal degrees. - -| `height/z` -| A numeric expression that represents the height/z value in meters. -| `crs` -| The optional `STRING` `'WGS-84-3D'`. - -| `srid` -| The optional `INTEGER` `4979`. - -|=== - -*Considerations:* - -|=== - -| If any argument provided to `point()` is `null`, `null` will be returned. -| If the `height/z` key and value is not provided, a 2D `POINT` in the _WGS 84_ CRS will be returned. -| If the coordinates are specified using `latitude` and `longitude`, the `crs` or `srid` fields are optional and inferred to be `'WGS-84-3D'` (`srid:4979`). -| If the coordinates are specified using `x` and `y`, then either the `crs` or `srid` field is required if a geographic CRS is desired. +| `point.withinBBox(point, lowerLeft, upperRight)` will return `null` if any of the arguments evaluate to `null`. +| Attempting to use `POINT` values with different Coordinate Reference Systems (such as WGS 84 2D and WGS 84 3D) will return `null`. +| `point.withinBBox` will handle crossing the 180th meridian in geographic coordinates. +| Switching the longitude of the `lowerLeft` and `upperRight` in geographic coordinates will switch the direction of the resulting bounding box. +| Switching the latitude of the `lowerLeft` and `upperRight` in geographic coordinates so that the former is north of the latter will result in an empty range. |=== -.+point()+ +.+point.withinBBox()+ ====== .Query [source, cypher] ---- -RETURN point({longitude: 56.7, latitude: 12.78, height: 8}) AS point +WITH + point({x: 0, y: 0, crs: 'cartesian'}) AS lowerLeft, + point({x: 10, y: 10, crs: 'cartesian'}) AS upperRight +RETURN point.withinBBox(point({x: 5, y: 5, crs: 'cartesian'}), lowerLeft, upperRight) AS result ---- -A 3D `POINT` with a `longitude` of `56.7`, a `latitude` of `12.78` and a height of `8` meters in the _WGS 84_ CRS is returned. +Checking if a point in _Cartesian_ CRS is contained in the bounding box. .Result [role="queryresult",options="header,footer",cols="1*` in which the order of all characters or elements in the given `STRING` or `LIST` have been reversed. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `STRING \| LIST` | The string or list to be reversed. +| *Returns* 3+| `STRING \| LIST` |=== -| Name | Description - -| `original` -| An expression that returns a `STRING`. - -|=== - -*Considerations:* +.Considerations |=== | `reverse(null)` returns `null`. +| See also xref:functions/list.adoc#functions-reverse[List functions -> reverse]. |=== @@ -578,8 +388,8 @@ RETURN reverse('anagram') [role="queryresult",options="header,footer",cols="1*` resulting from the splitting of the given `STRING` around matches of the given delimiter. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -split(original, splitDelimiter) ----- - -*Returns:* - -|=== - -| `LIST` - +.Details |=== - -*Arguments:* -[options="header"] -|=== -| Name | Description - -| `original` -| An expression that returns a `STRING`. - -| `splitDelimiter` -| The `STRING` with which to split `original`. - +| *Syntax* 3+| `split(original, splitDelimiters)` +| *Description* 3+| Returns a `LIST` resulting from the splitting of the given `STRING` around matches of the given delimiter(s). +.3+| *Arguments* | *Name* | *Type* | *Description* +| `original` | `STRING` | The string to be split. +| `splitDelimiters` | `STRING \| LIST` | The string with which to split the original string. +| *Returns* 3+| `LIST` |=== -*Considerations:* - +.Considerations |=== | `split(null, splitDelimiter)` return `null`. @@ -783,8 +529,8 @@ RETURN split('one,two', ',') [role="queryresult",options="header,footer",cols="1*+ +| toStringOrNull(11.5) | toStringOrNull('already a string') | toStringOrNull(true) | dateString | datetimeString | durationString | list +| "11.5" | "already a string" | "true" | "1984-10-11" | "1984-10-11T12:31:14.341+01:00[Europe/Stockholm]" | "PT11M" | 7+d|Rows: 1 |=== @@ -1061,36 +727,16 @@ toStringOrNull(['A', 'B', 'C']) AS list [[functions-toupper]] == toUpper() -`toUpper()` returns the given `STRING` in uppercase. - -*Syntax:* - -[source, syntax, role="noheader"] ----- -toUpper(original) ----- - -*Returns:* - -|=== - -| `STRING` - +.Details |=== - -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `input` -| A string to be converted into uppercase. - +| *Syntax* 3+| `toUpper(input)` +| *Description* 3+| Returns the given `STRING` in uppercase. +.2+| *Arguments* | *Name* | *Type* | *Description* +| `input` | `STRING` | A string to be converted into uppercase. +| *Returns* 3+| `STRING` |=== -*Considerations:* - +.Considerations |=== | `toUpper(null)` returns `null`. @@ -1111,8 +757,8 @@ RETURN toUpper('hello') [role="queryresult",options="header,footer",cols="1*` | A list representing the first vector. +| `b` | `LIST` | A list representing the second vector. +| *Returns* 3+| `FLOAT` +|=== + +For more details, see the {link-vector-indexes}#similarity-functions[vector index documentation]. + +.Considerations +|=== + +| `vector.similarity.cosine(NULL, NULL)` returns `NULL`. +| `vector.similarity.cosine(NULL, b)` returns `NULL`. +| `vector.similarity.cosine(a, NULL)` returns `NULL`. +| Both vectors must be of the same dimension. +| Both vectors must be {link-vector-indexes}#indexes-vector-similarity-cosine[*valid*] with respect to cosine similarity. +| The implementation is identical to that of the latest available vector index provider (`vector-2.0`). + +|=== + + +[[functions-similarity-euclidean]] +== vector.similarity.euclidean() + +.Details +|=== +| *Syntax* 3+| `vector.similarity.euclidean(a, b)` +| *Description* 3+| Returns a `FLOAT` representing the similarity between the argument vectors based on their Euclidean distance. +.3+| *Arguments* | *Name* | *Type* | *Description* +| `a` | `LIST` | A list representing the first vector. +| `b` | `LIST` | A list representing the second vector. +| *Returns* 3+| `FLOAT` +|=== + +For more details, see the {link-vector-indexes}#similarity-functions[vector index documentation]. + +.Considerations +|=== + +| `vector.similarity.euclidean(NULL, NULL)` returns `NULL`. +| `vector.similarity.euclidean(NULL, b)` returns `NULL`. +| `vector.similarity.euclidean(a, NULL)` returns `NULL`. +| Both vectors must be of the same dimension. +| Both vectors must be {link-vector-indexes}#indexes-vector-similarity-euclidean[*valid*] with respect to Euclidean similarity. +| The implementation is identical to that of the latest available vector index provider (`vector-2.0`). + +|=== + + + +.k-Nearest Neighbors +====== + +_k_-nearest neighbor queries return the _k_ entities with the highest similarity scores based on comparing their associated vectors with a query vector. Such queries can be run against vector indexes in the form of _approximate_ _k_-nearest neighbor (k-ANN) queries, whose returned entities have a high probability of being among the true _k_ nearest neighbors. However, they can also be expressed as an exhaustive search using vector similarity functions directly. While this is typically significantly slower than using an index, it is exact rather than approximate and does not require an existing index. This can be useful for one-off queries on small sets of data. -.k-Nearest Neighbors -====== To create the graph used in this example, run the following query in an empty Neo4j database: [source, cypher, role=test-setup] @@ -46,8 +106,8 @@ This returns the two nearest neighbors. [role="queryresult",options="header,footer",cols="2*` representing the first vector. - -| `b` -| A `LIST` representing the second vector. - -|=== - -*Considerations:* -|=== - -| `vector.similarity.cosine(NULL, NULL)` returns `NULL`. -| `vector.similarity.cosine(NULL, b)` returns `NULL`. -| `vector.similarity.cosine(a, NULL)` returns `NULL`. -| Both vectors must be of the same dimension. -| Both vectors must be {link-vector-indexes}#indexes-vector-similarity-cosine[*valid*] with respect to cosine similarity. -| The implementation is identical to that of the latest available vector index provider (`vector-2.0`). - -|=== - -[[functions-similarity-euclidean]] -== vector.similarity.euclidean() - -`vector.similarity.euclidean()` returns a `FLOAT` representing the similarity between the argument vectors based on their Euclidean distance. For more details, see the {link-vector-indexes}#indexes-vector-similarity-euclidean[vector index documentation]. - -[source, syntax] ----- -vector.similarity.euclidean(a, b) ----- - -*Returns:* - -|=== - -| `FLOAT` - -|=== - -*Arguments:* - -[options="header"] -|=== -| Name | Description - -| `a` -| A `LIST` representing the first vector. - -| `b` -| A `LIST` representing the second vector. - -|=== - -*Considerations:* -|=== - -| `vector.similarity.euclidean(NULL, NULL)` returns `NULL`. -| `vector.similarity.euclidean(NULL, b)` returns `NULL`. -| `vector.similarity.euclidean(a, NULL)` returns `NULL`. -| Both vectors must be of the same dimension. -| Both vectors must be {link-vector-indexes}#indexes-vector-similarity-euclidean[*valid*] with respect to Euclidean similarity. -| The implementation is identical to that of the latest available vector index provider (`vector-2.0`). - -|=== From 8e0598a4d18f5b4f34ad86b0e6f350296002735c Mon Sep 17 00:00:00 2001 From: JoelBergstrand Date: Mon, 2 Sep 2024 09:41:50 +0200 Subject: [PATCH 25/64] Standalone Order by, Skip/Offset, and Limit (#1027) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds documentation for standalone Order by, Skip/Offset, and Limit clause and introduction of the Offset keyword. Implementation of [CIP-168](https://docs.google.com/document/d/1fKnZHtJcP7A9ulbVJV3JfitM1AcMs4kz_hdAxDoNc2U/edit?usp=sharing) Questions: - Should the ORDER BY, LIMIT, SKIP, OFFSET pages be collected into one page, or an additional page added, to reflect that they now can be used as one clause now? - Should the Clauses index page be modified to reflect that ORDER BY, LIMIT, SKIP, OFFSET can be used as a standalone clause instead of only as subclauses? Corresponding [PR](https://github.com/neo-technology/neo4j/pull/26710) --------- Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- modules/ROOT/images/graph_limit_clause.svg | 72 +------- modules/ROOT/images/graph_order_by_clause.svg | 51 +----- modules/ROOT/images/graph_skip_clause.svg | 72 +------- .../gql-conformance/supported-mandatory.adoc | 9 +- modules/ROOT/pages/clauses/index.adoc | 5 +- modules/ROOT/pages/clauses/limit.adoc | 108 ++++++++--- modules/ROOT/pages/clauses/order-by.adoc | 124 ++++++++----- modules/ROOT/pages/clauses/skip.adoc | 168 +++++++++++++----- ...ions-additions-removals-compatibility.adoc | 35 +++- 9 files changed, 326 insertions(+), 318 deletions(-) diff --git a/modules/ROOT/images/graph_limit_clause.svg b/modules/ROOT/images/graph_limit_clause.svg index 10d6ef05f..5a21cdd1b 100644 --- a/modules/ROOT/images/graph_limit_clause.svg +++ b/modules/ROOT/images/graph_limit_clause.svg @@ -1,71 +1 @@ - - - - - - -L - - - -N0 - -name = 'A' - - - -N4 - -name = 'E' - - - -N0->N4 - - -KNOWS - - - -N3 - -name = 'D' - - - -N0->N3 - - -KNOWS - - - -N2 - -name = 'C' - - - -N0->N2 - - -KNOWS - - - -N1 - -name = 'B' - - - -N0->N1 - - -KNOWS - - - +KNOWSKNOWSKNOWSKNOWSPersonname:'Erika'Personname:'Andy'Personname:'David'Personname:'Charlotte'Personname:'Bernard' \ No newline at end of file diff --git a/modules/ROOT/images/graph_order_by_clause.svg b/modules/ROOT/images/graph_order_by_clause.svg index 71ffc6faf..a42046fcc 100644 --- a/modules/ROOT/images/graph_order_by_clause.svg +++ b/modules/ROOT/images/graph_order_by_clause.svg @@ -1,50 +1 @@ - - - - - - -L - - - -N0 - -name = 'A' -age = 34 -length = 170 - - - -N1 - -name = 'B' -age = 36 - - - -N0->N1 - - -KNOWS - - - -N2 - -name = 'C' -age = 32 -length = 185 - - - -N1->N2 - - -KNOWS - - - +KNOWSKNOWSPersonname:'Charlotte'age:32length:185Personname:'Bernard'age:36Personname:'Andy'age:34length:170 \ No newline at end of file diff --git a/modules/ROOT/images/graph_skip_clause.svg b/modules/ROOT/images/graph_skip_clause.svg index 10d6ef05f..5a21cdd1b 100644 --- a/modules/ROOT/images/graph_skip_clause.svg +++ b/modules/ROOT/images/graph_skip_clause.svg @@ -1,71 +1 @@ - - - - - - -L - - - -N0 - -name = 'A' - - - -N4 - -name = 'E' - - - -N0->N4 - - -KNOWS - - - -N3 - -name = 'D' - - - -N0->N3 - - -KNOWS - - - -N2 - -name = 'C' - - - -N0->N2 - - -KNOWS - - - -N1 - -name = 'B' - - - -N0->N1 - - -KNOWS - - - +KNOWSKNOWSKNOWSKNOWSPersonname:'Erika'Personname:'Andy'Personname:'David'Personname:'Charlotte'Personname:'Bernard' \ No newline at end of file diff --git a/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc b/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc index 478988f85..e2d4fa6f7 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc @@ -57,9 +57,8 @@ The only way to guarantee row order in Neo4j is to use xref:clauses/order-by.ado | 14.9 | -| xref:clauses/skip.adoc[`SKIP`] -| Cypher only supports `SKIP`, which is a GQL-supported synonym to `OFFSET`. - +| xref:clauses/order-by.adoc[`ORDER BY`], xref:clauses/skip.adoc[`SKIP`], xref::clauses/skip.adoc#offset-synonym[`OFFSET`], xref:clauses/limit.adoc[`LIMIT`] +| | 14.10 | @@ -118,8 +117,8 @@ The only way to guarantee row order in Neo4j is to use xref:clauses/order-by.ado | 16.19 | -| xref:clauses/skip.adoc[`SKIP`] -| Cypher only supports `SKIP` , which is a GQL-supported synonym to `OFFSET`. +| xref:clauses/skip.adoc[`SKIP`], xref::clauses/skip.adoc#offset-synonym[`OFFSET`] +| | 19.3 | diff --git a/modules/ROOT/pages/clauses/index.adoc b/modules/ROOT/pages/clauses/index.adoc index 36d0f19a4..d0e421713 100644 --- a/modules/ROOT/pages/clauses/index.adoc +++ b/modules/ROOT/pages/clauses/index.adoc @@ -63,12 +63,15 @@ m| xref::clauses/where.adoc[WHERE] m| xref::clauses/order-by.adoc[ORDER BY [ASC[ENDING\] \| DESC[ENDING\]\]] | A sub-clause following `RETURN` or `WITH`, specifying that the output should be sorted in either ascending (the default) or descending order. +As of Neo4j 5.24, it can also be used as a standalone clause. -m| xref::clauses/skip.adoc[SKIP] +m| xref::clauses/skip.adoc[SKIP] / xref::clauses/skip.adoc#offset-synonym[`OFFSET`] | Defines from which row to start including the rows in the output. +As of Neo4j 5.24, it can be used as a standalone clause. m| xref::clauses/limit.adoc[LIMIT] | Constrains the number of rows in the output. +As of Neo4j 5.24, it can be used as a standalone clause. |=== diff --git a/modules/ROOT/pages/clauses/limit.adoc b/modules/ROOT/pages/clauses/limit.adoc index 056fa5cae..cc29cf861 100644 --- a/modules/ROOT/pages/clauses/limit.adoc +++ b/modules/ROOT/pages/clauses/limit.adoc @@ -5,29 +5,41 @@ `LIMIT` constrains the number of returned rows. -`LIMIT` accepts any expression that evaluates to a positive integer and does not refer to nodes or relationships. +`LIMIT` accepts any expression that evaluates to a positive `INTEGER` and does not refer to nodes or relationships. -image:graph_limit_clause.svg[] +[NOTE] +Neo4j does not guarantee the results generated by `LIMIT`. +The only clause that guarantees a specific row order is xref:clauses/order-by.adoc[`ORDER BY`]. + +[[example-graph]] +== Example graph + +The following graph is used for the examples below: + +image::graph_limit_clause.svg[width="600", role="middle"] + +To recreate it, run the following query against an empty Neo4j database: -//// [source, cypher, role=test-setup] ---- CREATE - (a {name: 'A'}), - (b {name: 'B'}), - (c {name: 'C'}), - (d {name: 'D'}), - (e {name: 'E'}), - (a)-[:KNOWS]->(b), - (a)-[:KNOWS]->(c), - (a)-[:KNOWS]->(d), - (a)-[:KNOWS]->(e) + (andy: Person {name: 'Andy'}), + (bernard: Person {name: 'Bernard'}), + (charlotte: Person {name: 'Charlotte'}), + (david: Person {name: 'David'}), + (erika: Person {name: 'Erika'}), + (andy)-[:KNOWS]->(bernard), + (andy)-[:KNOWS]->(charlotte), + (andy)-[:KNOWS]->(david), + (andy)-[:KNOWS]->(erika) ---- -//// +[[examples]] +== Examples -[[limit-subset-rows]] -== Return a limited subset of the rows + +.Return a limited subset of the rows +==== To return a limited subset of the rows, use this syntax: @@ -46,15 +58,16 @@ Limit to 3 rows by the example query. [role="queryresult",options="header,footer",cols="1*(b), - (b)-[:KNOWS]->(c) + (andy: Person {name: 'Andy', age: 34, length: 170}), + (bernard: Person {name: 'Bernard', age: 36}), + (charlotte: Person {name: 'Charlotte', age: 32, length: 185}), + (andy)-[:KNOWS]->(bernard), + (bernard)-[:KNOWS]->(charlotte) ---- -//// - -[NOTE] -==== -Strings that contain special characters can have inconsistent or non-deterministic ordering in Neo4j. -For details, see xref::values-and-types/property-structural-constructed.adoc#property-types-sip-note[Sorting of special characters]. -==== [[order-nodes-by-property]] == Order nodes by property @@ -41,7 +40,7 @@ For details, see xref::values-and-types/property-structural-constructed.adoc#pro `ORDER BY` is used to sort the output. .Query -[source, cypher, indent=0] +[source, cypher] ---- MATCH (n) RETURN n.name, n.age @@ -54,9 +53,9 @@ The nodes are returned, sorted by their name. [role="queryresult",options="header,footer",cols="2* -| "A" | 34 | 170 -| "C" | 32 | 185 +| "Bernard" | 36 | +| "Andy" | 34 | 170 +| "Charlotte" | 32 | 185 3+d|Rows: 3 |=== @@ -153,7 +152,7 @@ The nodes are returned, sorted by their properties. By adding `DESC[ENDING]` after the variable to sort on, the sort will be done in reverse order. .Query -[source, cypher, indent=0] +[source, cypher] ---- MATCH (n) RETURN n.name, n.age @@ -166,9 +165,9 @@ The example returns the nodes, sorted by their name in reverse order. [role="queryresult",options="header,footer",cols="2* | "B" | 36 +| 170 | "Andy" | 34 +| 185 | "Charlotte" | 32 +| | "Bernard" | 36 3+d|Rows: 3 |=== @@ -209,7 +208,7 @@ For example, this can be used to control the order of items in the list produced The `MERGE` and `SET` clauses also have ordering dependencies which can be controlled this way. .Query -[source, cypher, indent=0] +[source, cypher] ---- MATCH (n) WITH n ORDER BY n.age @@ -222,7 +221,7 @@ The list of names built from the `collect` aggregating function contains the nam [role="queryresult",options="header,footer",cols="1*(b), - (a)-[:KNOWS]->(c), - (a)-[:KNOWS]->(d), - (a)-[:KNOWS]->(e) + (andy: Person {name: 'Andy'}), + (bernard: Person {name: 'Bernard'}), + (charlotte: Person {name: 'Charlotte'}), + (david: Person {name: 'David'}), + (erika: Person {name: 'Erika'}), + (andy)-[:KNOWS]->(bernard), + (andy)-[:KNOWS]->(charlotte), + (andy)-[:KNOWS]->(david), + (andy)-[:KNOWS]->(erika) ---- -//// +[[examples]] +== Examples -[[skip-first-three-rows]] -== Skip first three rows +.Skip the first three rows +==== -To return a subset of the result, starting from the fourth result, use the following syntax: +The following query returns a subset of the result, starting from the fourth result. .Query -[source, cypher, indent=0] +[source, cypher] ---- MATCH (n) RETURN n.name @@ -43,25 +52,24 @@ ORDER BY n.name SKIP 3 ---- -The first three nodes are skipped, and only the last two are returned in the result. - .Result [role="queryresult",options="header,footer",cols="1* Date: Wed, 4 Sep 2024 11:11:20 +0100 Subject: [PATCH 26/64] Add azure import example (#1008) --- modules/ROOT/pages/clauses/load-csv.adoc | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/modules/ROOT/pages/clauses/load-csv.adoc b/modules/ROOT/pages/clauses/load-csv.adoc index fd19b94e7..f8f90ddcc 100644 --- a/modules/ROOT/pages/clauses/load-csv.adoc +++ b/modules/ROOT/pages/clauses/load-csv.adoc @@ -170,6 +170,45 @@ Added 4 nodes, Set 8 properties, Added 4 labels [role=label--enterprise-edition label--not-on-aura] === Import from cloud URIs +[role=label--new-5.24] +==== Import from an Azure Cloud Storage URI + +You can import data from a CSV file hosted in an Azure Cloud Storage URI. + +.Import artists name and year information from an Azure Cloud Storage URI +==== + +.azb://azb-account/azb-container/artists.csv +[source, csv, filename="artists.csv"] +---- +1,ABBA,1992 +2,Roxette,1986 +3,Europe,1979 +4,The Cardigans,1992 +---- + +.Query +[source, cypher, role=test-skip] +---- +LOAD CSV FROM 'azb://azb-account/azb-container/artists.csv' AS row +MERGE (a:Artist {name: row[1], year: toInteger(row[2])}) +RETURN a.name, a.year +---- + +.Result +[role="queryresult",options="header,footer",cols="2* Date: Mon, 9 Sep 2024 09:32:50 +0200 Subject: [PATCH 27/64] LOAD CSV fixes (#1037) --- modules/ROOT/pages/clauses/load-csv.adoc | 6 ++++-- ...cations-additions-removals-compatibility.adoc | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/modules/ROOT/pages/clauses/load-csv.adoc b/modules/ROOT/pages/clauses/load-csv.adoc index f8f90ddcc..de374e266 100644 --- a/modules/ROOT/pages/clauses/load-csv.adoc +++ b/modules/ROOT/pages/clauses/load-csv.adoc @@ -170,6 +170,8 @@ Added 4 nodes, Set 8 properties, Added 4 labels [role=label--enterprise-edition label--not-on-aura] === Import from cloud URIs + +[[azure-cloud-storage]] [role=label--new-5.24] ==== Import from an Azure Cloud Storage URI @@ -209,7 +211,7 @@ Added 4 nodes, Set 8 properties, Added 4 labels |=== ==== - +[[google-cloud-storage]] [role=label--new-5.21] ==== Import from a Google Cloud Storage URI @@ -249,7 +251,7 @@ Added 4 nodes, Set 8 properties, Added 4 labels |=== ==== - +[[aws-s3]] [role=label--new-5.19] ==== Import from an AWS S3 URI diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index 5366e5626..a54081900 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -73,6 +73,18 @@ REMOVE n[$prop] | Added the ability to dynamically reference properties in xref:clauses/set.adoc#set-dynamically-a-property[SET] and xref:clauses/remove.adoc#remove-remove-a-property-dynamically[REMOVE] clauses. +a| +label:functionality[] +label:new[] +[source, cypher, role=noheader] +---- +LOAD CSV FROM 'azb://azb-account/azb-container/artists.csv' AS row +MERGE (a:Artist {name: row[1], year: toInteger(row[2])}) +RETURN a.name, a.year +---- + +| Extension of the xref:clauses/load-csv.adoc#azure-cloud-storage[LOAD CSV] clause to allow loading CSV files from Azure Cloud Storage URIs. + |=== [[cypher-deprecations-additions-removals-5.23]] @@ -213,7 +225,7 @@ LOAD CSV FROM 'gs://gs-bucket/artists.csv' AS row MERGE (a:Artist {name: row[1], year: toInteger(row[2])}) RETURN a.name, a.year ---- -| Extension of the xref:clauses/load-csv.adoc#import-from-cloud-uris[LOAD CSV] clause to allow loading CSV files from Google Cloud Storage URIs. +| Extension of the xref:clauses/load-csv.adoc#google-cloud-storage[LOAD CSV] clause to allow loading CSV files from Google Cloud Storage URIs. a| @@ -381,7 +393,7 @@ LOAD CSV FROM 's3://artists.csv' AS row MERGE (a:Artist {name: row[1], year: toInteger(row[2])}) RETURN a.name, a.year ---- -| Extension of the xref:clauses/load-csv.adoc#import-from-an-aws-s3-uri[LOAD CSV] clause to allow loading CSV files from AWS S3 URIs. +| Extension of the xref:clauses/load-csv.adoc#aws-s3[LOAD CSV] clause to allow loading CSV files from AWS S3 URIs. a| label:functionality[] From 3f51cb2b2e057e5d746ae21c9fc17b99e6c5e907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:00:44 +0200 Subject: [PATCH 28/64] Add brittleness information to id()/elementId() functions (#1035) --- modules/ROOT/pages/clauses/order-by.adoc | 9 +++------ modules/ROOT/pages/functions/scalar.adoc | 24 +++++++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/modules/ROOT/pages/clauses/order-by.adoc b/modules/ROOT/pages/clauses/order-by.adoc index 4e38ea640..feb5bb766 100644 --- a/modules/ROOT/pages/clauses/order-by.adoc +++ b/modules/ROOT/pages/clauses/order-by.adoc @@ -113,12 +113,9 @@ The nodes are returned, sorted by their internal ID. |=== [NOTE] -==== -Keep in mind that Neo4j reuses its internal IDs when nodes and relationships are deleted. -This means that applications using, and relying on, internal Neo4j IDs, are brittle or at risk of making mistakes. -It is therefore recommended to use application-generated IDs instead. -==== - +Neo4j reuses its internal IDs when nodes and relationships are deleted. +Applications relying on internal Neo4j IDs are, as a result, brittle and can be inaccurate. +It is recommended to use application-generated IDs instead. [[order-nodes-by-expression]] == Order nodes by expression diff --git a/modules/ROOT/pages/functions/scalar.adoc b/modules/ROOT/pages/functions/scalar.adoc index 48f431be0..7a5c76fab 100644 --- a/modules/ROOT/pages/functions/scalar.adoc +++ b/modules/ROOT/pages/functions/scalar.adoc @@ -6,7 +6,6 @@ Scalar functions return a single value. - [IMPORTANT] ==== The `length()` and `size()` functions are quite similar, and so it is important to take note of the difference. @@ -191,8 +190,8 @@ However, no guarantees are given regarding the order of the returned ID values o Outside of the scope of a single transaction, no guarantees are given about the mapping between ID values and elements. . Neo4j reuses its internal IDs when nodes and relationships are deleted. -This means that applications using, and relying on internal Neo4j IDs, are brittle or at risk of making mistakes. -It is therefore recommended to rather use application-generated IDs. +Applications relying on internal Neo4j IDs are, as a result, brittle and can be inaccurate. +It is therefore recommended to use application-generated IDs. .Considerations @@ -361,22 +360,29 @@ It is recommended to use xref:functions/scalar.adoc#functions-elementid[`element |=== -The function `id()` returns a node or a relationship identifier, unique by an object type and a database. +There are important considerations to bear in mind when using `id()`: + +. The function `id()` returns a node or a relationship identifier, unique by an object type and a database. Therefore, `id()` can return the same value for both nodes and relationships in the same database. -Neo4j implements the id so that every node and relationship in a database has an identifier. +. Neo4j implements the ID so that every node and relationship in a database has an identifier. The identifier for a node or relationship is guaranteed to be unique among other nodes' and relationships' identifiers in the same database, within the scope of a single transaction. +. Neo4j reuses its internal IDs when nodes and relationships are deleted. +Applications relying on internal Neo4j IDs are, as a result, brittle and can be inaccurate. +It is therefore recommended to use application-generated IDs instead. + + [NOTE] ==== On a link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/composite-databases/concepts/[composite database], the `id()` function should be used with caution. It is recommended to use xref:functions/scalar.adoc#functions-elementid[`elementId()`] instead. -When called in database-specific subqueries, the resulting id value for a node or relationship is local to that database. -The local id for nodes or relationships from different databases may be the same. +When called in database-specific subqueries, the resulting ID value for a node or relationship is local to that database. +The local ID for nodes or relationships from different databases may be the same. -When called from the root context of a query, the resulting value is an extended id for the node or relationship. -The extended id is likely different from the local id for the same node or relationship. +When called from the root context of a query, the resulting value is an extended ID for the node or relationship. +The extended ID is likely different from the local ID for the same node or relationship. ==== From a1a10848306d5ef57ca22e2f45a54e8dc3c41c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:59:50 +0200 Subject: [PATCH 29/64] Clean up some function pages (#1039) --- modules/ROOT/images/graph_list_functions.svg | 92 +--------------- .../ROOT/images/graph_numeric_functions.svg | 100 +----------------- .../ROOT/images/graph_scalar_functions.svg | 92 +--------------- .../ROOT/images/graph_spatial_functions.svg | 41 +------ modules/ROOT/pages/functions/aggregating.adoc | 2 +- modules/ROOT/pages/functions/list.adoc | 31 +++--- .../pages/functions/mathematical-numeric.adoc | 23 ++-- modules/ROOT/pages/functions/scalar.adoc | 65 ++++++------ modules/ROOT/pages/functions/spatial.adoc | 39 +++---- 9 files changed, 88 insertions(+), 397 deletions(-) diff --git a/modules/ROOT/images/graph_list_functions.svg b/modules/ROOT/images/graph_list_functions.svg index 88b6c8672..82ad32e38 100644 --- a/modules/ROOT/images/graph_list_functions.svg +++ b/modules/ROOT/images/graph_list_functions.svg @@ -1,91 +1 @@ - - - - - - -L - - - -N0 - -Person, Developer - -name = 'Alice' -age = 38 -eyes = 'brown' - - - -N2 - -name = 'Charlie' -age = 53 -eyes = 'green' - - - -N0->N2 - - -KNOWS - - - -N1 - -name = 'Bob' -age = 25 -eyes = 'blue' - - - -N0->N1 - - -KNOWS - - - -N3 - -name = 'Daniel' -age = 54 -eyes = 'brown' - - - -N2->N3 - - -KNOWS - - - -N1->N3 - - -KNOWS - - - -N4 - -eyes = 'blue' -array = ['one', 'two', 'three'] -name = 'Eskil' -age = 41 - - - -N1->N4 - - -MARRIED - - - +KNOWSKNOWSKNOWSKNOWSMARRIEDAdministratorname:'Charlie'age:53eyes:'Green'Administratorname:'Bob'age:25eyes:'Blue'Developername:'Alice'age:38eyes:'Brown'Administratorname:'Daniel'age:53eyes:'Brown'Designername:'Eskil'age:41eyes:'Blue'likedColors:['Pink', 'Yellow', 'Black'] \ No newline at end of file diff --git a/modules/ROOT/images/graph_numeric_functions.svg b/modules/ROOT/images/graph_numeric_functions.svg index 78b904b14..82ad32e38 100644 --- a/modules/ROOT/images/graph_numeric_functions.svg +++ b/modules/ROOT/images/graph_numeric_functions.svg @@ -1,99 +1 @@ - - - - - - -L - - - -N0 - -A - -name = 'Alice' -age = 38 -eyes = 'brown' - - - -N2 - -C - -name = 'Charlie' -age = 53 -eyes = 'green' - - - -N0->N2 - - -KNOWS - - - -N1 - -B - -name = 'Bob' -age = 25 -eyes = 'blue' - - - -N0->N1 - - -KNOWS - - - -N3 - -D - -name = 'Daniel' -age = 54 -eyes = 'brown' - - - -N2->N3 - - -KNOWS - - - -N1->N3 - - -KNOWS - - - -N4 - -E - -eyes = 'blue' -array = ['one', 'two', 'three'] -name = 'Eskil' -age = 41 - - - -N1->N4 - - -MARRIED - - - +KNOWSKNOWSKNOWSKNOWSMARRIEDAdministratorname:'Charlie'age:53eyes:'Green'Administratorname:'Bob'age:25eyes:'Blue'Developername:'Alice'age:38eyes:'Brown'Administratorname:'Daniel'age:53eyes:'Brown'Designername:'Eskil'age:41eyes:'Blue'likedColors:['Pink', 'Yellow', 'Black'] \ No newline at end of file diff --git a/modules/ROOT/images/graph_scalar_functions.svg b/modules/ROOT/images/graph_scalar_functions.svg index 549084a40..82ad32e38 100644 --- a/modules/ROOT/images/graph_scalar_functions.svg +++ b/modules/ROOT/images/graph_scalar_functions.svg @@ -1,91 +1 @@ - - - - - - -L - - - -N0 - -Developer - -name = 'Alice' -age = 38 -eyes = 'brown' - - - -N2 - -name = 'Charlie' -age = 53 -eyes = 'green' - - - -N0->N2 - - -KNOWS - - - -N1 - -name = 'Bob' -age = 25 -eyes = 'blue' - - - -N0->N1 - - -KNOWS - - - -N3 - -name = 'Daniel' -age = 54 -eyes = 'brown' - - - -N2->N3 - - -KNOWS - - - -N1->N3 - - -KNOWS - - - -N4 - -eyes = 'blue' -liked_colors = ['pink', 'yellow', 'black'] -name = 'Eskil' -age = 41 - - - -N1->N4 - - -MARRIED - - - +KNOWSKNOWSKNOWSKNOWSMARRIEDAdministratorname:'Charlie'age:53eyes:'Green'Administratorname:'Bob'age:25eyes:'Blue'Developername:'Alice'age:38eyes:'Brown'Administratorname:'Daniel'age:53eyes:'Brown'Designername:'Eskil'age:41eyes:'Blue'likedColors:['Pink', 'Yellow', 'Black'] \ No newline at end of file diff --git a/modules/ROOT/images/graph_spatial_functions.svg b/modules/ROOT/images/graph_spatial_functions.svg index b9d6b4db3..180186928 100644 --- a/modules/ROOT/images/graph_spatial_functions.svg +++ b/modules/ROOT/images/graph_spatial_functions.svg @@ -1,40 +1 @@ - - - - - - -L - - - -N0 - -TrainStation - -latitude = 55.672874 -longitude = 12.56459 -city = 'Copenhagen' - - - -N1 - -Office - -latitude = 55.611784 -longitude = 12.994341 -city = 'Malmo' - - - -N0->N1 - - -TRAVEL_ROUTE - - - +TRAVEL_ROUTETrainStationlatitude:55.672874longitude:12.564590city:'Copenhagen'Officelatitude:55.611784longitude:12.994341city:'Malmö' \ No newline at end of file diff --git a/modules/ROOT/pages/functions/aggregating.adoc b/modules/ROOT/pages/functions/aggregating.adoc index 238404787..2976c3666 100644 --- a/modules/ROOT/pages/functions/aggregating.adoc +++ b/modules/ROOT/pages/functions/aggregating.adoc @@ -17,7 +17,7 @@ To learn more about how Cypher handles aggregations performed on zero rows, refe The following graph is used for the examples below: -image::graph_aggregating_functions.svg[] +image::graph_aggregating_functions.svg[role="middle", width="700"] To recreate the graph, run the following query against an empty Neo4j database: diff --git a/modules/ROOT/pages/functions/list.adoc b/modules/ROOT/pages/functions/list.adoc index 2c16b1298..1ff0cd547 100644 --- a/modules/ROOT/pages/functions/list.adoc +++ b/modules/ROOT/pages/functions/list.adoc @@ -8,22 +8,23 @@ List functions return lists of different data entities. Further details and examples of lists may be found in xref::values-and-types/lists.adoc[Lists] and xref::syntax/operators.adoc#query-operators-list[List operators]. +[[example-graph]] == Example graph The following graph is used for the examples below: -image:graph_list_functions.svg[] +image::graph_list_functions.svg[role="middle", width="700"] -To recreate the graph, run the following query in an empty Neo4j database: +To recreate the graph, run the following query against an empty Neo4j database: [source, cypher, role=test-setup] ---- CREATE - (alice:Person:Developer {name:'Alice', age: 38, eyes: 'brown'}), - (bob {name: 'Bob', age: 25, eyes: 'blue'}), - (charlie {name: 'Charlie', age: 53, eyes: 'green'}), - (daniel {name: 'Daniel', age: 54, eyes: 'brown'}), - (eskil {name: 'Eskil', age: 41, eyes: 'blue', array: ['one', 'two', 'three']}), + (alice:Developer {name:'Alice', age: 38, eyes: 'Brown'}), + (bob:Administrator {name: 'Bob', age: 25, eyes: 'Blue'}), + (charlie:Administrator {name: 'Charlie', age: 53, eyes: 'Green'}), + (daniel:Adminstrator {name: 'Daniel', age: 54, eyes: 'Brown'}), + (eskil:Designer {name: 'Eskil', age: 41, eyes: 'blue', likedColors: ['Pink', 'Yellow', 'Black']}), (alice)-[:KNOWS]->(bob), (alice)-[:KNOWS]->(charlie), (bob)-[:KNOWS]->(daniel), @@ -68,7 +69,7 @@ A `LIST` containing the names of all the properties on the node bound to |=== | keys(a) -| ["eyes","name","age"] +| ["eyes", "name", "age"] 1+d|Rows: 1 |=== @@ -115,7 +116,7 @@ A `LIST` containing all the labels of the node bound to `a` is returned. |=== | labels(a) -| ["Person","Developer"] +| ["Developer"] 1+d|Rows: 1 |=== @@ -160,8 +161,8 @@ A `LIST` containing all the nodes in the path `p` is returned. [role="queryresult",options="header,footer",cols="1*` comprising all but the first element of the `array` property are returned. +The property named `likedColors` and a `LIST` comprising all but the first element of the `likedColors` property are returned. .Result [role="queryresult",options="header,footer",cols="2*(bob), (alice)-[:KNOWS]->(charlie), (bob)-[:KNOWS]->(daniel), (charlie)-[:KNOWS]->(daniel), (bob)-[:MARRIED]->(eskil) ---- -//// - [[functions-abs]] == abs() @@ -55,7 +57,8 @@ CREATE .Query [source, cypher, indent=0] ---- -MATCH (a), (e) WHERE a.name = 'Alice' AND e.name = 'Eskil' RETURN a.age, e.age, abs(a.age - e.age) +MATCH (a), (e) WHERE a.name = 'Alice' AND e.name = 'Eskil' +RETURN a.age, e.age, abs(a.age - e.age) ---- The absolute value of the age difference is returned. diff --git a/modules/ROOT/pages/functions/scalar.adoc b/modules/ROOT/pages/functions/scalar.adoc index 7a5c76fab..459102044 100644 --- a/modules/ROOT/pages/functions/scalar.adoc +++ b/modules/ROOT/pages/functions/scalar.adoc @@ -6,33 +6,29 @@ Scalar functions return a single value. -[IMPORTANT] -==== -The `length()` and `size()` functions are quite similar, and so it is important to take note of the difference. +[[example-graph]] +== Example graph -Function `length()`:: Only works for xref::functions/scalar.adoc#functions-length[paths]. -Function `size()`:: Only works for the three types: xref::functions/scalar.adoc#functions-size-of-string[`STRING` values], xref::functions/scalar.adoc#functions-size[lists], xref::functions/scalar.adoc#functions-size-of-pattern-comprehension[pattern comprehension]. -==== +The following graph is used for the examples below: -image:graph_scalar_functions.svg[] +image::graph_scalar_functions.svg[role="middle", width="700"] + +To recreate the graph, run the following query against an empty Neo4j database: -//// [source, cypher, role=test-setup] ---- CREATE - (alice:Developer {name:'Alice', age: 38, eyes: 'brown'}), - (bob {name: 'Bob', age: 25, eyes: 'blue'}), - (charlie {name: 'Charlie', age: 53, eyes: 'green'}), - (daniel {name: 'Daniel', age: 54, eyes: 'brown'}), - (eskil {name: 'Eskil', age: 41, eyes: 'blue', liked_colors: ['pink', 'yellow', 'black']}), + (alice:Developer {name:'Alice', age: 38, eyes: 'Brown'}), + (bob:Administrator {name: 'Bob', age: 25, eyes: 'Blue'}), + (charlie:Administrator {name: 'Charlie', age: 53, eyes: 'Green'}), + (daniel:Adminstrator {name: 'Daniel', age: 54, eyes: 'Brown'}), + (eskil:Designer {name: 'Eskil', age: 41, eyes: 'blue', likedColors: ['Pink', 'Yellow', 'Black']}), (alice)-[:KNOWS]->(bob), (alice)-[:KNOWS]->(charlie), (bob)-[:KNOWS]->(daniel), (charlie)-[:KNOWS]->(daniel), (bob)-[:MARRIED]->(eskil) ---- -//// - [role=label--new-5.13] [[functions-char_length]] @@ -162,7 +158,7 @@ RETURN coalesce(a.hairColor, a.eyes) |=== | coalesce(a.hairColor, a.eyes) -| "brown" +| "Brown" 1+d|Rows: 1 |=== @@ -282,8 +278,8 @@ RETURN endNode(r) [role="queryresult",options="header,footer",cols="1*(malmo) ---- @@ -88,8 +91,8 @@ A 2D `POINT` with a `longitude` of `56.7` and a `latitude` of `12.78` in the _WG [role="queryresult",options="header,footer",cols="1*+ +| p +| 1+d|Rows: 1 |=== From 265064e8ba0b8d675a6115e6a3ece9b1d7f8ce1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Wed, 11 Sep 2024 12:39:13 +0200 Subject: [PATCH 30/64] fix CALL query in clause composition page (#1038) --- modules/ROOT/pages/clauses/clause-composition.adoc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/clauses/clause-composition.adoc b/modules/ROOT/pages/clauses/clause-composition.adoc index 5b56aa926..fa560590f 100644 --- a/modules/ROOT/pages/clauses/clause-composition.adoc +++ b/modules/ROOT/pages/clauses/clause-composition.adoc @@ -572,6 +572,10 @@ Later invocations of the subquery can observe writes made by earlier invocations ====== Using the same example graph as above, this example shows the table of intermediate results and the state of the graph after each clause for the following query: +[NOTE] +The below query uses a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] (introduced in Neo4j 5.23) to import variables into the `CALL` subquery. +If you are using an older version of Neo4j, use an xref:subqueries/call-subquery.adoc#importing-with[importing `WITH` clause] instead. + [source,cypher] ---- MATCH (john:Person {name: 'John'}) @@ -579,9 +583,8 @@ SET john.friends = [] WITH john MATCH (john)-[:FRIEND]->(friend) WITH john, friend -CALL { - WITH john, friend - WITH *, john.friends AS friends +CALL (john, friend) { + WITH john.friends AS friends SET john.friends = friends + friend.name } ---- @@ -756,7 +759,7 @@ label = "{Person\|name = \'Maria\'\l}" | First invocation of ---- -WITH *, john.friends AS friends +WITH john.friends AS friends ---- | [options="header",cols="2m, 1m, 1m"] @@ -850,7 +853,7 @@ label = "{Person\|name = \'Maria\'\l}" | Second invocation of ---- -WITH *, john.friends AS friends +WITH john.friends AS friends ---- | [options="header",cols="2m, 1m, 1m"] From 51c3495f297f1b08bf2cdaffe985c4c4390416a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Fri, 13 Sep 2024 14:28:46 +0200 Subject: [PATCH 31/64] Document Cypher features that are not in GQL (#1033) --- modules/ROOT/content-nav.adoc | 1 + .../gql-conformance/additional-cypher.adoc | 599 ++++++++++++++++++ .../pages/appendix/gql-conformance/index.adoc | 10 +- .../gql-conformance/supported-mandatory.adoc | 3 +- 4 files changed, 609 insertions(+), 4 deletions(-) create mode 100644 modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc diff --git a/modules/ROOT/content-nav.adoc b/modules/ROOT/content-nav.adoc index f51ddf907..2eabb7c4c 100644 --- a/modules/ROOT/content-nav.adoc +++ b/modules/ROOT/content-nav.adoc @@ -130,6 +130,7 @@ *** xref:appendix/gql-conformance/unsupported-mandatory.adoc[] *** xref:appendix/gql-conformance/supported-optional.adoc[] *** xref:appendix/gql-conformance/analogous-cypher.adoc[] +*** xref:appendix/gql-conformance/additional-cypher.adoc[] ** xref:appendix/tutorials/index.adoc[] *** xref:appendix/tutorials/basic-query-tuning.adoc[] *** xref:appendix/tutorials/advanced-query-tuning.adoc[] diff --git a/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc b/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc new file mode 100644 index 000000000..2a33e5d4c --- /dev/null +++ b/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc @@ -0,0 +1,599 @@ +:description: Information about Cypher features not included in GQL. += Additional Cypher features + +While the link:https://www.iso.org/standard/76120.html[GQL Standard] incorporates a lot of capabilities in Cypher, Cypher contains additional features that are not part of GQL and no GQL alternatives currently exist for them. +This page covers those Cypher features. + +[[clauses]] +== Clauses + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:clauses/load-csv.adoc[`LOAD CSV`] +| Import data from CSV files. + +| xref:clauses/merge.adoc[`MERGE`] +| Ensures that a pattern exists in the graph. +Either the pattern already exists, or it needs to be created. + +|=== + +[[subqueries]] +== Subqueries + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:subqueries/subqueries-in-transactions.adoc[`CALL { …​ } IN TRANSACTIONS]` +| `CALL` subqueries executed in separate, inner transactions, producing intermediate commits. + +| xref:subqueries/collect.adoc[`COLLECT`] +| Used to create a list with the rows returned by a subquery. + +| xref:subqueries/count.adoc[`COUNT`] +| Used to count the number of rows returned by a subquery. + +| xref:subqueries/existential.adoc[`EXISTS`] +| Used to discover if a specified pattern exists at least once in the graph +|=== + + +[[values-and-types]] +== Values and types + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:values-and-types/spatial.adoc[`POINT` values] +| Spatial values. + +| xref:values-and-types/maps.adoc#query-operators-list[`MAP` values]. +| Map values - the GQL equivalent is Records. + +|=== + + +[[comprehensions-and-projections]] +== Comprehensions and projections + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:values-and-types/lists.adoc#cypher-list-comprehension[List comprehension] +| Syntactic construct for creating a `LIST` based on existing lists. + +| xref:values-and-types/maps.adoc#cypher-map-comprehension[Map projection] +| Constructs `MAP` projections from nodes, relationships, and other `MAP` values. + +| xref:values-and-types/lists.adoc#cypher-pattern-comprehension[Pattern comprehension] +| Syntactic construct for creating a `LIST` based on matchings of a pattern. +|=== + + +[[functions]] +== Functions + +[[database-functions]] +=== Database functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/database.adoc#functions-database-nameFromElementId[`db.nameFromElementId()`] +| Resolves the database name for the given element id. + +|=== + +[[genai-functions]] +=== GenAI functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:genai-integrations.adoc#single-embedding[`genai.vector.encode()`] +| Generates a vector embedding for a single value. + +|=== + + +[[graph-functions]] +=== Graph functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/graph.adoc#functions-graph-by-elementid[`graph.byElementId()`] +| Returns the graph reference with the given element id. It is only supported in the `USE` clause, on composite databases. + +| xref:functions/graph.adoc#functions-graph-byname[`graph.byName()`] +| Returns the graph reference of the given name. It is only supported in the `USE` clause, on composite databases. + +| xref:functions/graph.adoc#functions-graph-names[`graph.names()`] +| Lists the names of graphs in the current database. + +| xref:functions/graph.adoc#functions-graph-propertiesByName[`graph.propertiesByName()`] +| Returns the `MAP` of properties associated with a graph. + +|=== + + +[[list-functions]] +=== List functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/list.adoc#functions-keys[`keys()`] +| Returns a `LIST` containing the `STRING` representations for all the property names of a `NODE`, `RELATIONSHIP`, or `MAP`. + +| xref:functions/list.adoc#functions-labels[`labels()`] +| Returns a `LIST` containing the `STRING` representations for all the labels of a `NODE`. + +| xref:functions/list.adoc#functions-nodes[`nodes()`] +| Returns a `LIST` containing all the `NODE` values in a `PATH`. + +| xref:functions/list.adoc#functions-range[`range()`] +| Returns a `LIST` comprising all `INTEGER` values within a specified range. + +| xref:functions/list.adoc#functions-reduce[`reduce()`] +| Runs an expression against individual elements of a `LIST`, storing the result of the expression in an accumulator. + +| xref:functions/list.adoc#functions-relationships[`relationships()`] +| Returns a `LIST` containing all the `RELATIONSHIP` values in a `PATH`. + +| xref:functions/list.adoc#functions-reverse-list[`reverse()`] +| Returns a `STRING` or `LIST` in which the order of all characters or elements in the given `STRING` or `LIST` have been reversed. + +| xref:functions/list.adoc#functions-tail[`tail()`] +| Returns all but the first element in a `LIST`. + +| xref:functions/list.adoc#functions-tobooleanlist[`toBooleanList()`] +| Converts a `LIST` of values to a `LIST` values. If any values are not convertible to `BOOLEAN` they will be null in the `LIST` returned. + +| xref:functions/list.adoc#functions-tofloatlist[`toFloatList()`] +| Converts a `LIST` to a `LIST` values. If any values are not convertible to `FLOAT` they will be null in the `LIST` returned. + +| xref:functions/list.adoc#functions-tointegerlist[`toIntegerList()`] +| Converts a `LIST` to a `LIST` values. If any values are not convertible to `INTEGER` they will be null in the `LIST` returned. + +| xref:functions/list.adoc#functions-tostringlist[`toStringList()`] +| Converts an `INTEGER`, `FLOAT`, `BOOLEAN`, `POINT` or temporal type (i.e. `DATE`, `ZONED TIME`, `LOCAL TIME`, `ZONED DATETIME`, `LOCAL DATETIME` or `DURATION`) value to a `STRING`, or null if the value cannot be converted. + +|=== + +[[load-csv-functions]] +=== LOAD CSV functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/load-csv.adoc#functions-file[`file()`] +| Returns the absolute path of the file that `LOAD CSV` is using. + +| xref:functions/load-csv.adoc#functions-linenumber[`lineNumber`] +|Returns the line number that `LOAD CSV` is currently using. + +|=== + + +[[logarithmic-functions]] +=== Logarithmic functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/mathematical-logarithmic.adoc#functions-e[`e()`] +| Returns the base of the natural logarithm, e. + +|=== + +[[numeric-functions]] +=== Numeric functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/mathematical-numeric.adoc#functions-isnan[`isNaN()`] +| Returns whether the given `INTEGER` or `FLOAT` is NaN. + +| xref:functions/mathematical-numeric.adoc#functions-rand[`rand()`] +| Returns a random `FLOAT` in the range from 0 (inclusive) to 1 (exclusive). + +| xref:functions/mathematical-numeric.adoc#functions-round[`round()`] +| Returns the value of a number rounded to the nearest `INTEGER`. + +| xref:functions/mathematical-numeric.adoc#functions-sign[`sign()`] +| Returns the signum of an `INTEGER` or `FLOAT`: 0 if the number is 0, -1 for any negative number, and 1 for any positive number. + +|=== + +[[predicate-functions]] +=== Predicate functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/predicate.adoc#functions-all[`all()`] +| Returns true if the predicate holds for all elements in the given `LIST`. + +| xref:functions/predicate.adoc#functions-any[`any()`] +| Returns true if the predicate holds for at least one element in the given `LIST`. + +| xref:functions/predicate.adoc#functions-isempty[`isEmpty()`] +| Checks whether a `STRING`, `MAP`, or `LIST` is empty. + +| xref:functions/predicate.adoc#functions-none[`none()`] +| Returns true if the predicate holds for no element in the given `LIST`. + +| xref:functions/predicate.adoc#functions-single[`single()`] +| Returns true if the predicate holds for exactly one of the elements in the given `LIST`. +|=== + + +[[scalar-functions]] +=== Scalar functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/scalar.adoc#functions-endnode[`endNode()`] +| Returns the end `NODE` of a `RELATIONSHIP`. + +| xref:functions/scalar.adoc#functions-head[`head()`] +| Returns the first element in a `LIST`. + +| xref:functions/scalar.adoc#functions-last[`last()`] +| Returns the last element in a `LIST`. + +| xref:functions/scalar.adoc#functions-properties[`properties()`] +| Returns a `MAP` containing all the properties of a `NODE`, `RELATIONSHIP`, or `MAP`. + +| xref:functions/scalar.adoc#functions-randomuuid[`randomUUID()`] +| Generates a random UUID. + +| xref:functions/scalar.adoc#functions-startnode[`startNode()`] +| Returns the start `NODE` of a `RELATIONSHIP`. + +| xref:functions/scalar.adoc#functions-type[`type()`] +| Returns a `STRING` representation of the `RELATIONSHIP` type. + +| xref:functions/scalar.adoc#functions-valueType[`valueType()`] +| Returns a `STRING` representation of the most precise value type that the given expression evaluates to. + +|=== + +[[spatial-functions]] +=== Spatial functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/spatial.adoc#functions-point[`point()`] +| Returns a 2D or 3D point object, given two or respectively three coordinate values in the Cartesian coordinate system or WGS 84 geographic coordinate system. + +| xref:functions/spatial.adoc#functions-point-distance[`point.distance()`] +| Returns a `FLOAT` representing the geodesic distance between any two points in the same CRS. + +| xref:functions/spatial.adoc#functions-point-withinBBox[`point.withinBBox()`] +| Returns true if the provided point is within the bounding box defined by the two provided points. + +|=== + + +[[string-functions]] +=== String functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/string.adoc#functions-replace[`replace()`] +| Returns a `STRING` in which all occurrences of a specified search `STRING` in the given `STRING` have been replaced by another (specified) replacement `STRING`. + +| xref:functions/string.adoc#functions-reverse[`reverse()`] +| Returns a `STRING` or `LIST` in which the order of all characters or elements in the given `STRING` or `LIST` have been reversed. + +| xref:functions/string.adoc#functions-split[`split()`] +| Returns a `LIST` resulting from the splitting of the given `STRING` around matches of the given delimiter(s). + +| xref:functions/string.adoc#functions-substring[`substring()`] +| Returns a substring of the given `STRING`, beginning with a 0-based index start. + +|=== + +[[trigonometric-functions]] +=== Trigonometric functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/mathematical-trigonometric.adoc#functions-atan2[`atan2()`] +| Returns the arctangent2 of a set of coordinates in radians. + +| xref:functions/mathematical-trigonometric.adoc#functions-haversin[`haversin()`] +| Returns half the versine of a number. + +| xref:functions/mathematical-trigonometric.adoc#functions-pi[`pi()`] +| Returns the mathematical constant pi. + +|=== + + +[[temporal-duration-functions]] +=== Temporal duration functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/temporal/duration.adoc#functions-duration-indays[`duration.inDays()`] +| Computes the `DURATION` between the `from` instant (inclusive) and the `to` instant (exclusive) in days. + +| xref:functions/temporal/duration.adoc#functions-duration-inmonths[`duration.inMonths()`] +| Computes the `DURATION` between the `from` instant (inclusive) and the `to` instant (exclusive) in months. + +| xref:functions/temporal/duration.adoc#functions-duration-inseconds[`duration.inSeconds()`] +| Computes the `DURATION` between the `from` instant (inclusive) and the `to` instant (exclusive) in seconds. + +|=== + +[[temporal-instant-functions]] +=== Temporal instant functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/temporal/index.adoc#functions-date-realtime[`date.realtime()`] +| Returns the current `DATE` instant using the realtime clock. + +| xref:functions/temporal/index.adoc#functions-date-statement[`date.statement()`] +| Returns the current `DATE` instant using the statement clock. + +| xref:functions/temporal/index.adoc#functions-date-transaction[`date.transaction()`] +| Returns the current `DATE` instant using the transaction clock. + +| xref:functions/temporal/index.adoc#functions-date-truncate[`date.truncate()`] +| Returns the current `DATE` instant using the transaction clock. + +| xref:functions/temporal/index.adoc#functions-datetime-fromepoch[`datetime.fromEpoch()`] +| Creates a `ZONED DATETIME` given the seconds and nanoseconds since the start of the epoch. + +| xref:functions/temporal/index.adoc#functions-datetime-fromepochmillis[`datetime.fromEpochMillis()`] +| Creates a `ZONED DATETIME` given the milliseconds since the start of the epoch. + +| xref:functions/temporal/index.adoc#functions-datetime-realtime[`datetime.realtime()`] +| Returns the current `ZONED DATETIME` instant using the realtime clock. + +| xref:functions/temporal/index.adoc#functions-datetime-statement[`datetime.statement()`] +| Returns the current `ZONED DATETIME` instant using the statement clock. + +| xref:functions/temporal/index.adoc#functions-datetime-transaction[`datetime.transaction()`] +| Returns the current `ZONED DATETIME` instant using the transaction clock. + +| xref:functions/temporal/index.adoc#functions-datetime-truncate[`datetime.truncate()`] +| Truncates the given temporal value to a `ZONED DATETIME` instant using the specified unit. + +| xref:functions/temporal/index.adoc#functions-localdatetime-realtime[`localdatetime.realtime()`] +| Returns the current `LOCAL DATETIME` instant using the realtime clock. + +| xref:functions/temporal/index.adoc#functions-localdatetime-statement[`localdatetime.statement()`] +| Returns the current `LOCAL DATETIME` instant using the statement clock. + +| xref:functions/temporal/index.adoc#functions-localdatetime-transaction[`localdatetime.transaction()`] +| Returns the current `LOCAL DATETIME` instant using the transaction clock. + +| xref:functions/temporal/index.adoc#functions-localdatetime-truncate[`localdatetime.truncate()`] +| Truncates the given temporal value to a `LOCAL DATETIME` instant using the specified unit. + +| xref:functions/temporal/index.adoc#functions-localtime-realtime[`localtime.realtime()`] +| Returns the current `LOCAL TIME` instant using the realtime clock. + +| xref:functions/temporal/index.adoc#functions-localtime-statement[`localtime.statement()`] +| Returns the current `LOCAL TIME` instant using the statement clock. + +| xref:functions/temporal/index.adoc#functions-localtime-transaction[`localtime.transaction()`] +| Returns the current `LOCAL TIME` instant using the transaction clock. + +| xref:functions/temporal/index.adoc#functions-localtime-truncate[`localtime.truncate()`] +| Truncates the given temporal value to a `LOCAL TIME` instant using the specified unit. + +| xref:functions/temporal/index.adoc#functions-time-realtime[`time.realtime()`] +| Returns the current `ZONED TIME` instant using the realtime clock. + +| xref:functions/temporal/index.adoc#functions-time-statement[`time.statement()`] +| Returns the current `ZONED TIME` instant using the statement clock. + +| xref:functions/temporal/index.adoc#functions-time-transaction[`time.transaction()`] +| Returns the current `ZONED TIME` instant using the transaction clock. + +| xref:functions/temporal/index.adoc#functions-time-truncate[`time.truncate()`] +| Truncates the given temporal value to a `ZONED TIME` instant using the specified unit. + +|=== + + +[[vector-functions]] +=== Vector functions + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:functions/vector.adoc#functions-similarity-cosine[`vector.similarity.cosine()`] +| Returns a `FLOAT` representing the similarity between the argument vectors based on their cosine. + +| xref:functions/vector.adoc#functions-similarity-cosine[`vector.similarity.euclidean()`] +| Returns a `FLOAT` representing the similarity between the argument vectors based on their Euclidean distance. +|=== + +[[indexes]] +== Indexes + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:indexes/search-performance-indexes/managing-indexes.adoc#create-range-index[Range indexes] +| Neo4j’s default index. +Supports most types of predicates. + +| xref:indexes/search-performance-indexes/managing-indexes.adoc#create-text-index[Text indexes] +| Solves predicates operating on `STRING` values. +Optimized for queries filtering with the `STRING` operators `CONTAINS` and `ENDS WITH`. + +| xref:indexes/search-performance-indexes/managing-indexes.adoc#create-point-index[Point indexes] +| Solves predicates on spatial `POINT` values. +Optimized for queries filtering on distance or within bounding boxes. + +| xref:indexes/search-performance-indexes/managing-indexes.adoc#create-lookup-index[Token lookup indexes] +| Only solves node label and relationship type predicates (i.e. they cannot solve any predicates filtering on properties). + +| xref:indexes/semantic-indexes/full-text-indexes.adoc#create-full-text-indexes[Full text indexes] +| Enables searching within the content of `STRING` properties and for similarity comparisons between query strings and `STRING` values stored in the database. + +| xref:indexes/semantic-indexes/vector-indexes.adoc#create-vector-index[Vector indexes] +| Enables similarity searches and complex analytical queries by representing nodes or properties as vectors in a multidimensional space. + +| xref:indexes/search-performance-indexes/index-hints.adoc[Index hints] +| Cypher allows for index hints to influence the planner when creating execution plans. +Index hints are specified with the `USING` keyword. + +|=== + +[[constraints]] +== Constraints + +GQL supports `GRAPH TYPES` as a way of constraining a graph schema, but does not support individual constraints. + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:constraints/examples.adoc#constraints-examples-node-uniqueness[Node property uniqueness constraints] +| Ensures that certain nodes have a set of specified properties whose combined value is unique when all properties exist on the node + +| xref:constraints/examples.adoc#constraints-examples-relationship-uniqueness[Relationship property uniqueness constraints] +| Ensures that certain relationships have a set of specified properties whose combined value is unique when all properties exist on the relationship. + +| xref:constraints/examples.adoc#constraints-examples-node-property-existence[Node property existence constraints] +| Ensures that certain nodes have a specified property. + +| xref:constraints/examples.adoc#constraints-examples-relationship-property-existence[Relationship property existence constraints] +| Ensures that certain relationships have a specified property. + +| xref:constraints/examples.adoc#constraints-examples-node-property-type[Node property type constraints] +| Ensures that certain nodes have a property of the required property type when the property exists on the node. + +| xref:constraints/examples.adoc#constraints-examples-relationship-property-type[Relationship property type constraints] +| Ensures that certain relationships have a property of the required property type when the property exists on the relationship. + +| xref:constraints/examples.adoc#constraints-examples-node-key[Node key constraints] +| Ensures that certain nodes have a set of specified properties whose combined value is unique and all properties in the set are present. + +| xref:constraints/examples.adoc#constraints-examples-relationship-key[Relationship key constraints] +| Ensures that certain relationships have a set of defined properties whose combined value is unique. It also ensures that all properties in the set are present. + +|=== + +[[operators]] +== Operators + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:syntax/operators.adoc#query-operator-comparison-string-specific[`STARTS WITH`, `CONTAINS`, `ENDS WITH`, and regular expressions]. +| `STRING` comparison operators. + +| xref:syntax/operators.adoc#query-operators-list[`IN`] +| `IN` predicate for `LIST` values. + +|=== + + +[[query-optimization]] +== Query optimization + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| xref:planning-and-tuning/index.adoc#profile-and-explain[`EXPLAIN`/`PROFILE`] +| Optionally prepended to queries to produce execution plans. +`EXPLAIN` will only generate an execution plan but not run the query; `PROFILE` will do both. + +| `CYPHER runtime=parallel` +| Cypher allows for setting the xref:planning-and-tuning/runtimes/concepts.adoc[runtime] of queries, determining how the query will be executed. +The available Cypher runtimes are: slotted, pipelined, parallel. + +| `CYPHER inferSchemaParts=off` +| Cypher allows for setting numerous query options. +For more information, see xref:planning-and-tuning/query-tuning.adoc[Query options]. + +|=== + + +[[administration]] +== Administration + +[NOTE] +The documentation for Cypher's administration commands is located in Neo4j's link:{neo4j-docs-base-uri}/operations-manual/{page-version}/[Operation Manual]. + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +| link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/[Database management] +| Commands to `CREATE`, `SHOW`, `ALTER`, and `DROP` standard and composite databases. + +| link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/aliases/manage-aliases-standard-databases/[Alias management] +| Commands to `CREATE`, `SHOW`, `ALTER`, and `DROP` database aliases. + +| link:{neo4j-docs-base-uri}/operations-manual/{page-version}/clustering/[Server management] +| Commands to administer servers in a cluster and the databases allocated to them. + +| link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/[Authentication and authorization] +| Commands to manage users, roles, and privileges. + +|=== \ No newline at end of file diff --git a/modules/ROOT/pages/appendix/gql-conformance/index.adoc b/modules/ROOT/pages/appendix/gql-conformance/index.adoc index 5b58aafb1..2aafc9772 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/index.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/index.adoc @@ -1,8 +1,8 @@ :description: Overview of Cypher's conformance to GQL. = GQL conformance -*Last updated*: 9 August 2024 + -*Neo4j version*: 5.23 +*Last updated*: 13 September 2024 + +*Neo4j version*: 5.24 GQL is the new link:https://www.iso.org/home.html[ISO] International Standard query language for graph databases. @@ -27,9 +27,13 @@ These are listed in the page xref:appendix/gql-conformance/unsupported-mandatory Neo4j is also working towards increasing its support of optional GQL features. These are listed in the page xref:appendix/gql-conformance/supported-optional.adoc[]. -Additionally, some optional GQL features not yet implemented in Cypher already have analogous Cypher equivalents. +Some optional GQL features not yet implemented in Cypher already have analogous Cypher equivalents. These features are listed in the page xref:appendix/gql-conformance/analogous-cypher.adoc[]. +Additionally, Cypher contains additional features that are not part of GQL and no GQL alternatives currently exist for them. +These features are listed in the page xref:appendix/gql-conformance/additional-cypher.adoc[]. + + [[gql-minimum-conformance]] == Note on minimum GQL conformance diff --git a/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc b/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc index e2d4fa6f7..6a8299b0e 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/supported-mandatory.adoc @@ -68,7 +68,8 @@ The only way to guarantee row order in Neo4j is to use xref:clauses/order-by.ado | 14.11 | | xref:clauses/return.adoc[`RETURN`] -| +| GQL defines the option to specify `RETURN ALL` (functionally equivalent to using `RETURN` on its own). +This is currently not available in Cypher. | 16.2 | From 12369ce9cf29684148e636894948b62e257a6208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Mon, 16 Sep 2024 10:55:41 +0200 Subject: [PATCH 32/64] Fix plans for Repeat(trail) and NullifyMetaData (#1043) --- .../operators/operators-detail.adoc | 100 ++++++++++-------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc b/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc index d6c0f97d8..4f9d332ed 100644 --- a/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc +++ b/modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc @@ -3969,7 +3969,7 @@ Total database accesses: 49, total allocated memory: 1200 == Repeat (Trail) // Repeat(Trail) -Given a start node, the `Repeat(Trail)` operator will traverse xref::patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path patterns] that cannot be solved with the xref::planning-and-tuning/operators/operators-detail.adoc#query-plan-varlength-expand-all[`VarLengthExpand(All)`] operator. +Given a start node, the `Repeat(Trail)` operator will traverse xref::patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path patterns] that cannot be solved (or solved efficiently) with the xref::planning-and-tuning/operators/operators-detail.adoc#query-plan-varlength-expand-all[`VarLengthExpand(All)`] operator. Similar to an xref::planning-and-tuning/operators/operators-detail.adoc#query-plan-apply[`Apply`] operator, it takes a single row from the left-hand side and applies the operators on the right-hand side. In contrast to `Apply`, however, it repeatedly applies these operators in accordance with the quantifiers on the quantified path pattern. In the following example, the operator will repeat twice and produce rows for both repetitions. @@ -3981,7 +3981,7 @@ In the following example, the operator will repeat twice and produce rows for bo [source, cypher] ---- PROFILE -MATCH (me:Person) ((a)-[:FRIENDS_WITH]-(b) WHERE a.name <> b.name){1,2} (friend:Person) +MATCH (me:Person) ((a)-[:FRIENDS_WITH]-(b)-[:FRIENDS_WITH]-(c) WHERE a.name <> b.name AND a.name <> c.name AND b.name <> c.name){1,2} (friend:Person) RETURN me, friend ---- @@ -3996,27 +3996,32 @@ Runtime version {neo4j-version-minor} Batch size 128 -+------------------+----+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ -| Operator | Id | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | -+------------------+----+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ -| +ProduceResults | 0 | me, friend | 15 | 48 | 0 | | | | | -| | +----+-----------------------------------------------------+----------------+------+---------+----------------+ | | | -| +Filter | 1 | friend:Person | 15 | 48 | 96 | | | | | -| | +----+-----------------------------------------------------+----------------+------+---------+----------------+ | | | -| +NullifyMetadata | 7 | | 15 | 48 | 0 | | | | | -| | +----+-----------------------------------------------------+----------------+------+---------+----------------+ | | | -| +Repeat(Trail) | 2 | (me) (...){1, 2} (friend) | 15 | 48 | 0 | 16784 | 0/0 | 1.146 | Fused in Pipeline 2 | -| |\ +----+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ -| | +Filter | 3 | not a.name = b.name AND isRepeatTrailUnique(anon_2) | 5 | 48 | 216 | | | | | -| | | +----+-----------------------------------------------------+----------------+------+---------+----------------+ | | | -| | +Expand(All) | 4 | (a)-[anon_2:FRIENDS_WITH]-(b) | 10 | 72 | 151 | | | | | -| | | +----+-----------------------------------------------------+----------------+------+---------+----------------+ | | | -| | +Argument | 5 | a | 14 | 38 | 0 | 3112 | 3/0 | 6.279 | Fused in Pipeline 1 | -| | +----+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ -| +NodeByLabelScan | 6 | me:Person | 14 | 14 | 15 | 376 | 1/0 | 3.970 | In Pipeline 0 | -+------------------+----+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ - -Total database accesses: 318, total allocated memory: 208 ++------------------+----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ +| Operator | Id | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | ++------------------+----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ +| +ProduceResults | 0 | me, friend | 2 | 34 | 136 | 0 | | | | +| | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| +Filter | 1 | friend:Person | 2 | 34 | 68 | | | | | +| | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| +NullifyMetadata | 9 | | 2 | 34 | 0 | | | | | +| | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| +Repeat(Trail) | 2 | (me) (...){1, 2} (friend) | 2 | 34 | 0 | 29792 | 0/0 | 1.696 | Fused in Pipeline 2 | +| |\ +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ +| | +Filter | 3 | NOT anon_5 = anon_3 AND (NOT cache[a.name] = cache[c.name] AND NOT cache[b.name] = cache[c.name]) AN | 1 | 34 | 92 | | | | | +| | | | | D isRepeatTrailUnique(anon_5) | | | | | | | | +| | | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| | +Expand(All) | 4 | (b)-[anon_5:FRIENDS_WITH]-(c) | 3 | 92 | 138 | | | | | +| | | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| | +Filter | 5 | NOT cache[a.name] = cache[b.name] AND isRepeatTrailUnique(anon_3) | 5 | 46 | 198 | | | | | +| | | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| | +Expand(All) | 6 | (a)-[anon_3:FRIENDS_WITH]-(b) | 10 | 66 | 100 | | | | | +| | | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| | +Argument | 7 | a | 15 | 34 | 0 | 15672 | 2/0 | 3.245 | Fused in Pipeline 1 | +| | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ +| +NodeByLabelScan | 8 | me:Person | 14 | 14 | 15 | 376 | 1/0 | 0.107 | In Pipeline 0 | ++------------------+----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ + +Total database accesses: 747, total allocated memory: 45832 ---- ====== @@ -4036,7 +4041,7 @@ It is only planned directly after `Repeat(Trail)`. [source, cypher] ---- PROFILE -MATCH (me:Person) ((a)-[:FRIENDS_WITH]-(b) WHERE a.name <> b.name){1,2} (friend:Person) +MATCH (me:Person) ((a)-[:FRIENDS_WITH]-(b)-[:FRIENDS_WITH]-(c) WHERE a.name <> b.name AND a.name <> c.name AND b.name <> c.name){1,2} (friend:Person) RETURN me, friend ---- @@ -4051,27 +4056,32 @@ Runtime version {neo4j-version-minor} Batch size 128 -+------------------+----+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ -| Operator | Id | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | -+------------------+----+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ -| +ProduceResults | 0 | me, friend | 15 | 48 | 0 | | | | | -| | +----+-----------------------------------------------------+----------------+------+---------+----------------+ | | | -| +Filter | 1 | friend:Person | 15 | 48 | 96 | | | | | -| | +----+-----------------------------------------------------+----------------+------+---------+----------------+ | | | -| +NullifyMetadata | 7 | | 15 | 48 | 0 | | | | | -| | +----+-----------------------------------------------------+----------------+------+---------+----------------+ | | | -| +Repeat(Trail) | 2 | (me) (...){1, 2} (friend) | 15 | 48 | 0 | 16784 | 0/0 | 1.146 | Fused in Pipeline 2 | -| |\ +----+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ -| | +Filter | 3 | not a.name = b.name AND isRepeatTrailUnique(anon_2) | 5 | 48 | 216 | | | | | -| | | +----+-----------------------------------------------------+----------------+------+---------+----------------+ | | | -| | +Expand(All) | 4 | (a)-[anon_2:FRIENDS_WITH]-(b) | 10 | 72 | 151 | | | | | -| | | +----+-----------------------------------------------------+----------------+------+---------+----------------+ | | | -| | +Argument | 5 | a | 14 | 38 | 0 | 3112 | 3/0 | 6.279 | Fused in Pipeline 1 | -| | +----+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ -| +NodeByLabelScan | 6 | me:Person | 14 | 14 | 15 | 376 | 1/0 | 3.970 | In Pipeline 0 | -+------------------+----+-----------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ - -Total database accesses: 318, total allocated memory: 208 ++------------------+----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ +| Operator | Id | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline | ++------------------+----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ +| +ProduceResults | 0 | me, friend | 2 | 34 | 136 | 0 | | | | +| | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| +Filter | 1 | friend:Person | 2 | 34 | 68 | | | | | +| | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| +NullifyMetadata | 9 | | 2 | 34 | 0 | | | | | +| | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| +Repeat(Trail) | 2 | (me) (...){1, 2} (friend) | 2 | 34 | 0 | 29792 | 0/0 | 1.696 | Fused in Pipeline 2 | +| |\ +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ +| | +Filter | 3 | NOT anon_5 = anon_3 AND (NOT cache[a.name] = cache[c.name] AND NOT cache[b.name] = cache[c.name]) AN | 1 | 34 | 92 | | | | | +| | | | | D isRepeatTrailUnique(anon_5) | | | | | | | | +| | | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| | +Expand(All) | 4 | (b)-[anon_5:FRIENDS_WITH]-(c) | 3 | 92 | 138 | | | | | +| | | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| | +Filter | 5 | NOT cache[a.name] = cache[b.name] AND isRepeatTrailUnique(anon_3) | 5 | 46 | 198 | | | | | +| | | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| | +Expand(All) | 6 | (a)-[anon_3:FRIENDS_WITH]-(b) | 10 | 66 | 100 | | | | | +| | | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+ | | | +| | +Argument | 7 | a | 15 | 34 | 0 | 15672 | 2/0 | 3.245 | Fused in Pipeline 1 | +| | +----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ +| +NodeByLabelScan | 8 | me:Person | 14 | 14 | 15 | 376 | 1/0 | 0.107 | In Pipeline 0 | ++------------------+----+------------------------------------------------------------------------------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+ + +Total database accesses: 747, total allocated memory: 45832 ---- ====== From 280593b3f755cd8f204169303c99058aa64618da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:09:35 +0200 Subject: [PATCH 33/64] Document OPTIONAL CALL (#1034) --- modules/ROOT/images/call_procedure.svg | 1 + modules/ROOT/pages/clauses/call.adoc | 391 ++++++++---------- ...ions-additions-removals-compatibility.adoc | 28 +- .../ROOT/pages/subqueries/call-subquery.adoc | 70 ++++ 4 files changed, 279 insertions(+), 211 deletions(-) create mode 100644 modules/ROOT/images/call_procedure.svg diff --git a/modules/ROOT/images/call_procedure.svg b/modules/ROOT/images/call_procedure.svg new file mode 100644 index 000000000..7cb856c93 --- /dev/null +++ b/modules/ROOT/images/call_procedure.svg @@ -0,0 +1 @@ +KNOWSKNOWSKNOWSDevelopername:'Andy'born:1991Administratorname:'David'born:1994nationality:'Swedish'Developername:'Beatrice'born:1985Administratorname:'Charlotte'born:1990 \ No newline at end of file diff --git a/modules/ROOT/pages/clauses/call.adoc b/modules/ROOT/pages/clauses/call.adoc index 652bdbc5d..d600d0bd4 100644 --- a/modules/ROOT/pages/clauses/call.adoc +++ b/modules/ROOT/pages/clauses/call.adoc @@ -1,170 +1,78 @@ :description: The `CALL` clause is used to call a procedure deployed in the database. - [[query-call]] = CALL procedure The `CALL` clause is used to call a procedure deployed in the database. -[[query-call-introduction]] -== Introduction - -Procedures are called using the `CALL` clause. - -[TIP] -==== +[NOTE] The `CALL` clause is also used to evaluate a subquery. -For descriptions of the `CALL` clause in this context, refer to xref::subqueries/call-subquery.adoc[`CALL {}` (subquery)]. -==== - -Each procedure call needs to specify all required procedure arguments. -This may be done either explicitly, by using a comma-separated list wrapped in parentheses after the procedure name, or implicitly by using available query parameters as procedure call arguments. -The latter form is available only in a so-called standalone procedure call, when the whole query consists of a single `CALL` clause. - -Most procedures return a stream of records with a fixed set of result fields, similar to how running a Cypher query returns a stream of records. -The `YIELD` sub-clause is used to explicitly select which of the available result fields are returned as newly-bound variables from the procedure call to the user or for further processing by the remaining query. -Thus, in order to be able to use `YIELD` for explicit columns, the names (and types) of the output parameters need be known in advance. -Each yielded result field may optionally be renamed using aliasing (i.e., `resultFieldName AS newName`). -All new variables bound by a procedure call are added to the set of variables already bound in the current scope. -It is an error if a procedure call tries to rebind a previously bound variable (i.e., a procedure call cannot shadow a variable that was previously bound in the current scope). -In a standalone procedure call, `+YIELD *+` can be used to select all columns. In this case, the name of the output parameters does not need to be known in advance. - -For more information on how to determine the input parameters for the `CALL` procedure and the output parameters for the `YIELD` procedure, see xref::clauses/call.adoc#call-view-the-signature-for-a-procedure[View the signature for a procedure]. - -Inside a larger query, the records returned from a procedure call with an explicit `YIELD` may be further filtered using a `WHERE` sub-clause followed by a predicate (similar to `+WITH ... WHERE ...+`). - -If the called procedure declares at least one result field, `YIELD` may generally not be omitted. -However `YIELD` may always be omitted in a standalone procedure call. -In this case, all result fields are yielded as newly-bound variables from the procedure call to the user. +For more information about the `CALL` clause in this context, refer to xref::subqueries/call-subquery.adoc[]. -Neo4j supports the notion of `VOID` procedures. -A `VOID` procedure is a procedure that does not declare any result fields and returns no result records and that has explicitly been declared as `VOID`. -Calling a `VOID` procedure may only have a side effect and thus does neither allow nor require the use of `YIELD`. -Calling a `VOID` procedure in the middle of a larger query will simply pass on each input record (i.e., it acts like `+WITH *+` in terms of the record stream). +For information about how to list procedures, see xref:clauses/listing-procedures.adoc[]. [NOTE] -==== Neo4j comes with a number of built-in procedures. For a list of these, see link:{neo4j-docs-base-uri}/operations-manual/{page-version}/reference/procedures[Operations Manual -> Procedures]. - Users can also develop custom procedures and deploy to the database. See link:{neo4j-docs-base-uri}/java-reference/{page-version}/extending-neo4j/procedures#extending-neo4j-procedures[Java Reference -> User-defined procedures] for details. -==== +[[example-graph]] +== Example graph + +The following graph is used for the examples below: -[[call-call-a-procedure-using-call]] -== Call a procedure using `CALL` +image::call_procedure.svg[width="400",role="middle"] -This calls the built-in procedure `db.labels`, which lists all labels used in the database. +To recreate it, run the following query against an empty Neo4j database: -//// [source, cypher, role=test-setup] ---- -CREATE (:User); -Create (:Administrator) +CREATE (andy:Developer {name: 'Andy', born: 1991}), + (beatrice:Developer {name: 'Beatrice', born: 1985}), + (charlotte:Administrator {name: 'Charlotte', born: 1990}), + (david:Administrator {name: 'David', born: 1994, nationality: 'Swedish'}), + (andy)-[:KNOWS]->(beatrice), + (beatrice)-[:KNOWS]->(charlotte), + (andy)-[:KNOWS]->(david) ---- -//// -.Query -[source, cypher] ----- -CALL db.labels() ----- +[[call-procedure-examples]] +== Examples -.Result -[role="queryresult",options="header,footer",cols="1* Procedures] or returned by a `SHOW PROCEDURES` query. + +.Find the argument names of `db.propertyKeys` [source, cypher] ---- -CALL dbms.checkConfigValue('server.bolt.enabled', 'true') +SHOW PROCEDURES YIELD name, signature +WHERE name = 'db.propertyKeys' +RETURN signature ---- .Result -[role="queryresult",options="header,footer",cols=""2*", 1) +YIELD node +RETURN n.name AS name, collect(node.name) AS connections ---- -Since the procedure call is part of a larger query, all outputs must be named explicitly. +Note that the result does not include the nodes in the graph without any outgoing `KNOWS` relationships connected to them. +.Result +[role="queryresult",options="header,footer",cols="2*", 1) +YIELD node +RETURN n.name AS name, collect(node.name) AS connections ---- -Since the procedure call is part of a larger query, all outputs must be named explicitly. +The result now includes the two nodes without any outgoing `KNOWS` relationships connected to them. + +.Result +[role="queryresult",options="header,footer",cols="2*(t) + RETURN collect(p) as players +} +RETURN t AS team, players +---- + +[source, cypher, role="noheader"] +---- +OPTIONAL CALL db.labels() YIELD label +RETURN label +---- + +| Introduced `OPTIONAL CALL` for optionally executing a xref:clauses/call.adoc#optiona-call[procedure] or xref:subqueries/call-subquery.adoc#optional-call[subquery] `CALL`. +Similar to xref:clauses/optional-match.adoc[`OPTIONAL MATCH`], any empty rows produced by the `OPTIONAL CALL` will return `null` and not affect the remainder of the procedure or subquery evaluation. + a| label:functionality[] label:new[] @@ -55,7 +78,7 @@ Introduced GQL conformant standalone xref::clauses/order-by.adoc#order-standalon a| label:functionality[] label:new[] -[source, cypher, role=noheader] +[source, cypher, role="noheader"] ---- SET n:$(label) REMOVE n:$(label) @@ -65,12 +88,11 @@ REMOVE n:$(label) a| label:functionality[] label:new[] -[source, cypher, role=noheader] +[source, cypher, role="noheader"] ---- SET n[$prop] = "hello world" REMOVE n[$prop] ---- - | Added the ability to dynamically reference properties in xref:clauses/set.adoc#set-dynamically-a-property[SET] and xref:clauses/remove.adoc#remove-remove-a-property-dynamically[REMOVE] clauses. a| diff --git a/modules/ROOT/pages/subqueries/call-subquery.adoc b/modules/ROOT/pages/subqueries/call-subquery.adoc index 84624ee19..44d2001c9 100644 --- a/modules/ROOT/pages/subqueries/call-subquery.adoc +++ b/modules/ROOT/pages/subqueries/call-subquery.adoc @@ -422,6 +422,76 @@ RETURN largeLists ==== +[role=label--new-5.24] +[[optional-call]] +== Optional subquery calls + +`OPTIONAL CALL` allows for optional execution of a `CALL` subquery. +Similar to xref:clauses/optional-match.adoc[`OPTIONAL MATCH`] any empty rows produced by the `OPTIONAL CALL` subquery will return `null`. + +.Difference between using `CALL` and `OPTIONAL CALL` +==== + +This example, which finds the friends of each `Player` and xref:functions/aggregating.adoc#functions-count[counts] the number of friends per player, highlights the difference between using `CALL` and `OPTIONAL CALL`. + +.Regular subquery `CALL` +[source, cypher] +---- +MATCH (p:Player) +CALL (p) { + MATCH (p)-[:FRIEND_OF]->(friend:Player) + RETURN friend +} +RETURN p.name AS playerName, count(friend) AS numberOfFriends +ORDER BY numberOfFriends +---- + +.Optional subquery `CALL` +[role="queryresult",options="header,footer",cols="2*m"] +|=== +| playerName | numberOfFriends + +| "Player B" | 1 +| "Player C" | 1 +| "Player A" | 2 + +2+d|Rows: 3 +|=== + +Note that no results are returned for `Player D`, `Player E`, and `Player F`, since they have no outgoing `FRIEND_OF` relationships connected to them. + +.Query using regular `OPTIONAL CALL` +[source, cypher] +---- +MATCH (p:Player) +OPTIONAL CALL (p) { + MATCH (p)-[:FRIEND_OF]->(friend:Player) + RETURN friend +} +RETURN p.name AS playerName, count(friend) AS numberOfFriends +ORDER BY numberOfFriends +---- + +Now, all `Player` nodes, regardless of whether they have any friends or not, are returned. +(Those without any outgoing `FRIEND_OF` relationships are returned with the result `0` because `count()` ignores `null` values.) + +.Result +[role="queryresult",options="header,footer",cols="2*m"] +|=== +| playerName | numberOfFriends + +| "Player D" | 0 +| "Player E" | 0 +| "Player F" | 0 +| "Player B" | 1 +| "Player C" | 1 +| "Player A" | 2 + +2+d|Rows: 6 +|=== + +==== + [[call-execution-order]] == Execution order of CALL subqueries From c151042b0e537f28b058e6484274a44d14bfaeb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:16:09 +0200 Subject: [PATCH 34/64] Bump express from 4.19.2 to 4.21.0 in the dev-dependencies group (#1044) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the dev-dependencies group with 1 update: [express](https://github.com/expressjs/express). Updates `express` from 4.19.2 to 4.21.0
Release notes

Sourced from express's releases.

4.21.0

What's Changed

New Contributors

Full Changelog: https://github.com/expressjs/express/compare/4.20.0...4.21.0

4.20.0

What's Changed

Important

  • IMPORTANT: The default depth level for parsing URL-encoded data is now 32 (previously was Infinity)
  • Remove link renderization in html while using res.redirect

Other Changes

... (truncated)

Changelog

Sourced from express's changelog.

4.21.0 / 2024-09-11

  • Deprecate res.location("back") and res.redirect("back") magic string
  • deps: serve-static@1.16.2
    • includes send@0.19.0
  • deps: finalhandler@1.3.1
  • deps: qs@6.13.0

4.20.0 / 2024-09-10

  • deps: serve-static@0.16.0
    • Remove link renderization in html while redirecting
  • deps: send@0.19.0
    • Remove link renderization in html while redirecting
  • deps: body-parser@0.6.0
    • add depth option to customize the depth level in the parser
    • IMPORTANT: The default depth level for parsing URL-encoded data is now 32 (previously was Infinity)
  • Remove link renderization in html while using res.redirect
  • deps: path-to-regexp@0.1.10
    • Adds support for named matching groups in the routes using a regex
    • Adds backtracking protection to parameters without regexes defined
  • deps: encodeurl@~2.0.0
    • Removes encoding of \, |, and ^ to align better with URL spec
  • Deprecate passing options.maxAge and options.expires to res.clearCookie
    • Will be ignored in v5, clearCookie will set a cookie with an expires in the past to instruct clients to delete the cookie
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=express&package-manager=npm_and_yarn&previous-version=4.19.2&new-version=4.21.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- package-lock.json | 261 +++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 142 insertions(+), 121 deletions(-) diff --git a/package-lock.json b/package-lock.json index 73be5181f..5714c2639 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "asciidoctor-kroki": "^0.18.1" }, "devDependencies": { - "express": "^4.19.2", + "express": "^4.21.0", "nodemon": "^3.1.4" } }, @@ -538,9 +538,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -551,7 +551,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -864,9 +864,9 @@ "dev": true }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "engines": { "node": ">= 0.8" @@ -933,37 +933,37 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1032,13 +1032,13 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1183,21 +1183,21 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, "engines": { "node": ">= 0.4" @@ -1219,9 +1219,9 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "dependencies": { "function-bind": "^1.1.2" @@ -1452,10 +1452,13 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge2": { "version": "1.4.1", @@ -1673,10 +1676,13 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1732,9 +1738,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", "dev": true }, "node_modules/pend": { @@ -1900,12 +1906,12 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -2111,9 +2117,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "dependencies": { "debug": "2.6.9", @@ -2134,6 +2140,15 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2141,32 +2156,32 @@ "dev": true }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/set-function-length": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", - "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, "dependencies": { - "define-data-property": "^1.1.2", + "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2936,9 +2951,9 @@ "dev": true }, "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "requires": { "bytes": "3.1.2", @@ -2949,7 +2964,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -3168,9 +3183,9 @@ "dev": true }, "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true }, "end-of-stream": { @@ -3219,37 +3234,37 @@ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, "express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -3306,13 +3321,13 @@ } }, "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -3412,18 +3427,18 @@ "dev": true }, "has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "requires": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" } }, "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true }, "has-symbols": { @@ -3433,9 +3448,9 @@ "dev": true }, "hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "requires": { "function-bind": "^1.1.2" @@ -3600,9 +3615,9 @@ "dev": true }, "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true }, "merge2": { @@ -3749,9 +3764,9 @@ "dev": true }, "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true }, "on-exit-leak-free": { @@ -3793,9 +3808,9 @@ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", "dev": true }, "pend": { @@ -3935,12 +3950,12 @@ } }, "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "requires": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" } }, "queue-microtask": { @@ -4064,9 +4079,9 @@ } }, "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "requires": { "debug": "2.6.9", @@ -4084,6 +4099,12 @@ "statuses": "2.0.1" }, "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4093,29 +4114,29 @@ } }, "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "requires": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" } }, "set-function-length": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", - "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, "requires": { - "define-data-property": "^1.1.2", + "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" } }, "setprototypeof": { diff --git a/package.json b/package.json index 624ebb8c1..25806c632 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "asciidoctor-kroki": "^0.18.1" }, "devDependencies": { - "express": "^4.19.2", + "express": "^4.21.0", "nodemon": "^3.1.4" }, "overrides": { From 3a2c82697defe11e6421b1a258ec6c843d5eabd6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:33:43 +0200 Subject: [PATCH 35/64] Bump nodemon from 3.1.4 to 3.1.7 in the dev-dependencies group (#1048) Bumps the dev-dependencies group with 1 update: [nodemon](https://github.com/remy/nodemon). Updates `nodemon` from 3.1.4 to 3.1.7
Release notes

Sourced from nodemon's releases.

v3.1.7

3.1.7 (2024-09-20)

Bug Fixes

v3.1.6

3.1.6 (2024-09-19)

Bug Fixes

v3.1.5

3.1.5 (2024-09-17)

Bug Fixes

  • add missing ignore option to type defintion of config (#2224) (254c2ab)
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=nodemon&package-manager=npm_and_yarn&previous-version=3.1.4&new-version=3.1.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5714c2639..4385aa990 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ }, "devDependencies": { "express": "^4.21.0", - "nodemon": "^3.1.4" + "nodemon": "^3.1.7" } }, "node_modules/@antora/asciidoc-loader": { @@ -1601,9 +1601,9 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/nodemon": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz", - "integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", + "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -3714,9 +3714,9 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "nodemon": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz", - "integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", + "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==", "dev": true, "requires": { "chokidar": "^3.5.2", diff --git a/package.json b/package.json index 25806c632..f58757d71 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ }, "devDependencies": { "express": "^4.21.0", - "nodemon": "^3.1.4" + "nodemon": "^3.1.7" }, "overrides": { "@antora/site-generator-default": { From 3de159eda8c341dde49a6e9b56750706722685ef Mon Sep 17 00:00:00 2001 From: Therese Magnusson Date: Wed, 25 Sep 2024 09:20:43 +0200 Subject: [PATCH 36/64] Added `DROP DATABASE name CASCADE ALIASES` (#1036) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Companion Pr to https://github.com/neo4j/docs-operations/pull/1805, ~~should probably wait for that to go in.~~ Documenting https://github.com/neo-technology/neo4j/pull/26465, ~~needs to wait until that has been merged.~~ --------- Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- ...eprecations-additions-removals-compatibility.adoc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index 3c1e57942..3c74a904e 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -95,6 +95,18 @@ REMOVE n[$prop] ---- | Added the ability to dynamically reference properties in xref:clauses/set.adoc#set-dynamically-a-property[SET] and xref:clauses/remove.adoc#remove-remove-a-property-dynamically[REMOVE] clauses. +a| +label:functionality[] +label:new[] +[source, cypher, role=noheader] +---- +DROP [COMPOSITE] DATABASE ... [RESTRICT \| CASCADE ALIAS[ES]] +---- + +| Added the ability to drop database aliases while deleting a database. +This will affect local database aliases targeting the database and constituent database aliases belonging to the composite database. +For more information, see link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/standard-databases/delete-databases/#delete-databases-with-aliases[Delete a database with local database aliases targeting it] and link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/composite-databases/delete-composite-databases/#composite-databases-delete-with-aliases[Delete a composite database with constituent database aliases]. + a| label:functionality[] label:new[] From cd26ff9d4cccc31a3a0db48d091bd0878a000561 Mon Sep 17 00:00:00 2001 From: Phil Wright <95368282+phil198@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:32:05 +0100 Subject: [PATCH 37/64] adding property rules to 5.21 additions (#1046) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- ...tions-additions-removals-compatibility.adoc | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index 3c74a904e..759aa7d4b 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -250,6 +250,23 @@ The column is a `STRING` value specifying a replacement function/procedure if th | Feature | Details +a| +label:functionality[] +label:new[] +[source, cypher, role=noheader] +---- +GRANT READ {*} ON GRAPH * FOR (n) WHERE n.securityLevel > 3 TO regularUsers +---- +[source, cypher, role=noheader] +---- +GRANT TRAVERSE ON GRAPH * FOR (n:Email) WHERE n.classification IS NULL TO regularUsers +---- +[source, cypher, role=noheader] +---- +DENY MATCH {*} ON GRAPH * FOR (n) WHERE n.classification <> 'UNCLASSIFIED' TO regularUsers +---- +| Introduction of link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/property-based-access-control[property-based access control] for read privileges. The ability to read, traverse and match nodes based on node property values is now supported in Enterprise Edition. + a| label:functionality[] label:new[] @@ -261,7 +278,6 @@ RETURN a.name, a.year ---- | Extension of the xref:clauses/load-csv.adoc#google-cloud-storage[LOAD CSV] clause to allow loading CSV files from Google Cloud Storage URIs. - a| label:functionality[] label:new[] From 4674ac58ec54151d6f1a989081d26ddbde6b540f Mon Sep 17 00:00:00 2001 From: Phil Wright <95368282+phil198@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:01:48 +0100 Subject: [PATCH 38/64] adding Auth Providers to deprecations-additions-removals-compatibility (#1042) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Therese Magnusson Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- ...ions-additions-removals-compatibility.adoc | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index 759aa7d4b..2f28f6f8f 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -119,6 +119,62 @@ RETURN a.name, a.year | Extension of the xref:clauses/load-csv.adoc#azure-cloud-storage[LOAD CSV] clause to allow loading CSV files from Azure Cloud Storage URIs. +a| +label:functionality[] +label:new[] +[source, cypher, role=noheader] +---- +CREATE USER bob +SET AUTH 'externalProviderName' { + SET ID 'userIdForExternalProvider' +} +SET AUTH 'native' { + SET PASSWORD 'password' + SET PASSWORD CHANGE REQUIRED +} +---- +| Added the ability set which link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/auth-providers.adoc[auth providers] apply to a user (Enterprise Edition). + +Administration of the native (username / password) auth via the new syntax is also now supported (Community Edition). + +a| +label:functionality[] +label:new[] +[source, cypher, role=noheader] +---- +ALTER USER bob +REMOVE AUTH 'native' +SET AUTH 'externalProviderName' { + SET ID 'userIdForExternalProvider' +} +---- +| Added the ability add and remove user link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/auth-providers.adoc[auth providers] via the `ALTER USER` command. + +Setting the native (username / password) auth provider via this new syntax is also supported (Community Edition), but removing any auth provider or setting a non-native auth provider is only supported in Enterprise Edition. + + +a| +label:functionality[] +label:new[] +[source, cypher, role="noheader"] +---- +SHOW USERS WITH AUTH +---- +a| +New support for `WITH AUTH` to allow display users' auth providers with a separate row per user per auth provider. + +a| +label:functionality[] +label:new[] + +[source, cypher, role="noheader"] +---- +SET AUTH +---- +a| +New privilege that allows a user to modify user link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/auth-providers.adoc[auth providers]. +This is a sub-privilege of the `ALTER USER` privilege. +Like all `GRANT`/`DENY` commands this is only available in Enterprise Edition. + |=== [[cypher-deprecations-additions-removals-5.23]] From 1006824cb405b3b63daa8cd7e082e67043c78dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:15:37 +0200 Subject: [PATCH 39/64] Update antora for 5.25 (#1050) --- antora.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/antora.yml b/antora.yml index c48e579e0..ef51b64c7 100644 --- a/antora.yml +++ b/antora.yml @@ -7,5 +7,5 @@ nav: asciidoc: attributes: neo4j-version: '5' - neo4j-version-minor: '5.24' - neo4j-version-exact: '5.24.0' + neo4j-version-minor: '5.25' + neo4j-version-exact: '5.25.0' From 632c23c0504c1187135586588321338d4da6f856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:21:42 +0200 Subject: [PATCH 40/64] Fix optional call link (#1051) --- .../pages/deprecations-additions-removals-compatibility.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index 2f28f6f8f..32396b495 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -45,7 +45,7 @@ OPTIONAL CALL db.labels() YIELD label RETURN label ---- -| Introduced `OPTIONAL CALL` for optionally executing a xref:clauses/call.adoc#optiona-call[procedure] or xref:subqueries/call-subquery.adoc#optional-call[subquery] `CALL`. +| Introduced `OPTIONAL CALL` for optionally executing a xref:clauses/call.adoc#optional-call[procedure] or xref:subqueries/call-subquery.adoc#optional-call[subquery] `CALL`. Similar to xref:clauses/optional-match.adoc[`OPTIONAL MATCH`], any empty rows produced by the `OPTIONAL CALL` will return `null` and not affect the remainder of the procedure or subquery evaluation. a| From 88e11aff1248b37f57ea62ff122a6fb0ca8dfb42 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 10:44:00 +0200 Subject: [PATCH 41/64] Bump @neo4j-documentation/macros from 1.0.2 to 1.0.4 in the prod-dependencies group (#1052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the prod-dependencies group with 1 update: [@neo4j-documentation/macros](https://github.com/neo4j-documentation/docs-refresh). Updates `@neo4j-documentation/macros` from 1.0.2 to 1.0.4
Commits
Maintainer changes

This version was pushed to npm by neo.neil, a new releaser for @​neo4j-documentation/macros since your current version.


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@neo4j-documentation/macros&package-manager=npm_and_yarn&previous-version=1.0.2&new-version=1.0.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4385aa990..fb8fd9d50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@neo4j-antora/antora-page-roles": "^0.3.1", "@neo4j-antora/antora-table-footnotes": "^0.3.2", "@neo4j-antora/mark-terms": "1.1.0", - "@neo4j-documentation/macros": "^1.0.2", + "@neo4j-documentation/macros": "^1.0.4", "@neo4j-documentation/remote-include": "^1.0.0", "asciidoctor-kroki": "^0.18.1" }, @@ -347,9 +347,9 @@ "integrity": "sha512-Cd/ZxJa0gKIGQZCgIg0td2vSYeLz30/31fBxJNeOmDQzUPqduOYRVx/C7uK0y0SI38APBr11LyeDhyQIU0wtGw==" }, "node_modules/@neo4j-documentation/macros": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@neo4j-documentation/macros/-/macros-1.0.2.tgz", - "integrity": "sha512-83w4HPxt9lx1cR6w/Zi741Fu8/IE8pAGHf3BxIvBE8M+XzdT1f1Y6EpbLFrdZjqKwlcomdhks1/+zxlAbVa1xg==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@neo4j-documentation/macros/-/macros-1.0.4.tgz", + "integrity": "sha512-lFBtBWIh8HCMBio2lPJ4+4S9kkZwGivEg8IUlJSNuOjfOvaSChcYgPjeTVSwzy1LF46v3xSthmZFrTT+91YdYA==" }, "node_modules/@neo4j-documentation/remote-include": { "version": "1.0.0", @@ -2808,9 +2808,9 @@ "integrity": "sha512-Cd/ZxJa0gKIGQZCgIg0td2vSYeLz30/31fBxJNeOmDQzUPqduOYRVx/C7uK0y0SI38APBr11LyeDhyQIU0wtGw==" }, "@neo4j-documentation/macros": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@neo4j-documentation/macros/-/macros-1.0.2.tgz", - "integrity": "sha512-83w4HPxt9lx1cR6w/Zi741Fu8/IE8pAGHf3BxIvBE8M+XzdT1f1Y6EpbLFrdZjqKwlcomdhks1/+zxlAbVa1xg==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@neo4j-documentation/macros/-/macros-1.0.4.tgz", + "integrity": "sha512-lFBtBWIh8HCMBio2lPJ4+4S9kkZwGivEg8IUlJSNuOjfOvaSChcYgPjeTVSwzy1LF46v3xSthmZFrTT+91YdYA==" }, "@neo4j-documentation/remote-include": { "version": "1.0.0", diff --git a/package.json b/package.json index f58757d71..6fa63e771 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "@neo4j-antora/antora-page-roles": "^0.3.1", "@neo4j-antora/antora-table-footnotes": "^0.3.2", "@neo4j-antora/mark-terms": "1.1.0", - "@neo4j-documentation/macros": "^1.0.2", + "@neo4j-documentation/macros": "^1.0.4", "@neo4j-documentation/remote-include": "^1.0.0", "asciidoctor-kroki": "^0.18.1" }, From 0b50dd30b00518960dfb072c8a61e7b8426e0727 Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Thu, 3 Oct 2024 21:54:15 +0100 Subject: [PATCH 42/64] Add Nodes 24 ad (#1053) --- publish.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/publish.yml b/publish.yml index cc1293bd9..8eedfac03 100644 --- a/publish.yml +++ b/publish.yml @@ -60,3 +60,11 @@ asciidoc: cross-mark: icon:times[] neo4j-base-uri: '' neo4j-docs-base-uri: /docs + # NODES 2024 AD + page-ad-overline-link: https://neo4j.registration.goldcast.io/events/03805ea9-fe3a-4cac-8c15-aa622666531a?utm_source=neodocs&utm_medium=banner&utm_campaign=std + page-ad-image: /assets/img/nodes-24.png + page-ad-title: Neo4j Online Developer Conference + page-ad-description: Join us on November 7 for live and unique tech talks over 24 hours across all timezones. + page-ad-link: https://neo4j.registration.goldcast.io/events/03805ea9-fe3a-4cac-8c15-aa622666531a?utm_source=neodocs&utm_medium=banner&utm_campaign=std + page-ad-underline-role: button + page-ad-underline: Register \ No newline at end of file From 7a2428741cf90a1fc6b158e4cbdc5fb7a9f1c429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Fri, 4 Oct 2024 08:53:58 +0200 Subject: [PATCH 43/64] Fix links to Auth providers in Ops Manual (#1054) --- .../deprecations-additions-removals-compatibility.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index 32396b495..2aef91c68 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -133,7 +133,7 @@ SET AUTH 'native' { SET PASSWORD CHANGE REQUIRED } ---- -| Added the ability set which link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/auth-providers.adoc[auth providers] apply to a user (Enterprise Edition). +| Added the ability set which link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/auth-providers[auth providers] apply to a user (Enterprise Edition). Administration of the native (username / password) auth via the new syntax is also now supported (Community Edition). @@ -148,7 +148,7 @@ SET AUTH 'externalProviderName' { SET ID 'userIdForExternalProvider' } ---- -| Added the ability add and remove user link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/auth-providers.adoc[auth providers] via the `ALTER USER` command. +| Added the ability add and remove user link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/auth-providers[auth providers] via the `ALTER USER` command. Setting the native (username / password) auth provider via this new syntax is also supported (Community Edition), but removing any auth provider or setting a non-native auth provider is only supported in Enterprise Edition. @@ -171,7 +171,7 @@ label:new[] + SET AUTH ---- a| -New privilege that allows a user to modify user link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/auth-providers.adoc[auth providers]. +New privilege that allows a user to modify user link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/auth-providers[auth providers]. This is a sub-privilege of the `ALTER USER` privilege. Like all `GRANT`/`DENY` commands this is only available in Enterprise Edition. From fa9e191d6de93851c52cb66a42b1d2e0cc6278fe Mon Sep 17 00:00:00 2001 From: Neil Dewhurst Date: Mon, 7 Oct 2024 22:48:09 +0100 Subject: [PATCH 44/64] fix link to image (#1055) --- publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/publish.yml b/publish.yml index 8eedfac03..49ad0451a 100644 --- a/publish.yml +++ b/publish.yml @@ -62,7 +62,7 @@ asciidoc: neo4j-docs-base-uri: /docs # NODES 2024 AD page-ad-overline-link: https://neo4j.registration.goldcast.io/events/03805ea9-fe3a-4cac-8c15-aa622666531a?utm_source=neodocs&utm_medium=banner&utm_campaign=std - page-ad-image: /assets/img/nodes-24.png + page-ad-image: https://neo4j.com/docs/assets/img/nodes-24.png page-ad-title: Neo4j Online Developer Conference page-ad-description: Join us on November 7 for live and unique tech talks over 24 hours across all timezones. page-ad-link: https://neo4j.registration.goldcast.io/events/03805ea9-fe3a-4cac-8c15-aa622666531a?utm_source=neodocs&utm_medium=banner&utm_campaign=std From c4de60d02f9357aa1c7d053fe980e40d9763270f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Mon, 14 Oct 2024 12:42:58 +0200 Subject: [PATCH 45/64] Clarify CALL subquery ambiguities (#1060) --- modules/ROOT/images/call_subquery_graph.svg | 10 +- .../ROOT/pages/subqueries/call-subquery.adoc | 102 ++++++++---------- 2 files changed, 50 insertions(+), 62 deletions(-) diff --git a/modules/ROOT/images/call_subquery_graph.svg b/modules/ROOT/images/call_subquery_graph.svg index 932cf79da..e7e2e2629 100644 --- a/modules/ROOT/images/call_subquery_graph.svg +++ b/modules/ROOT/images/call_subquery_graph.svg @@ -1,9 +1,9 @@ - - + + - - + + - + diff --git a/modules/ROOT/pages/subqueries/call-subquery.adoc b/modules/ROOT/pages/subqueries/call-subquery.adoc index 44d2001c9..0461834ce 100644 --- a/modules/ROOT/pages/subqueries/call-subquery.adoc +++ b/modules/ROOT/pages/subqueries/call-subquery.adoc @@ -30,14 +30,9 @@ CREATE (teamA:Team {name: 'Team A'}), (playerF:Player {name: 'Player F', age: 35}), (playerA)-[:PLAYS_FOR]->(teamA), (playerB)-[:PLAYS_FOR]->(teamA), - (playerC)-[:PLAYS_FOR]->(teamA), (playerD)-[:PLAYS_FOR]->(teamB), (playerE)-[:PLAYS_FOR]->(teamC), (playerF)-[:PLAYS_FOR]->(teamC), - (playerA)-[:FRIEND_OF]->(playerB), - (playerA)-[:FRIEND_OF]->(playerC), - (playerB)-[:FRIEND_OF]->(playerF), - (playerC)-[:FRIEND_OF]->(playerD), (teamA)-[:OWES {dollars: 1500}]->(teamB), (teamA)-[:OWES {dollars: 3000}]->(teamB), (teamB)-[:OWES {dollars: 1700}]->(teamC), @@ -92,7 +87,6 @@ CALL () { SET p.age = p.age + 1 RETURN p.age AS newAge } -WITH x, newAge MATCH (p:Player {name: 'Player A'}) RETURN x AS iteration, newAge, p.age AS totalAge ---- @@ -139,7 +133,7 @@ RETURN t AS team, players | players | (:Team {name: "Team A"}) -| [(:Player {name: "Player C", age: 19}), (:Player {name: "Player B", age: 23}), (:Player {name: "Player A", age: 24})] +| (:Player {name: "Player B", age: 23}), (:Player {name: "Player A", age: 24})] | (:Team {name: "Team B"}) | [(:Player {name: "Player D", age: 30})] @@ -432,60 +426,60 @@ Similar to xref:clauses/optional-match.adoc[`OPTIONAL MATCH`] any empty rows pro .Difference between using `CALL` and `OPTIONAL CALL` ==== -This example, which finds the friends of each `Player` and xref:functions/aggregating.adoc#functions-count[counts] the number of friends per player, highlights the difference between using `CALL` and `OPTIONAL CALL`. +This example, which finds the team that each `Player` plays for, highlights the difference between using `CALL` and `OPTIONAL CALL`. .Regular subquery `CALL` [source, cypher] ---- MATCH (p:Player) CALL (p) { - MATCH (p)-[:FRIEND_OF]->(friend:Player) - RETURN friend + MATCH (p)-[:PLAYS_FOR]->(team:Team) + RETURN team } -RETURN p.name AS playerName, count(friend) AS numberOfFriends -ORDER BY numberOfFriends +RETURN p.name AS playerName, team.name AS team ---- -.Optional subquery `CALL` +.Result [role="queryresult",options="header,footer",cols="2*m"] |=== -| playerName | numberOfFriends +| playerName | team -| "Player B" | 1 -| "Player C" | 1 -| "Player A" | 2 +| "Player A" | "Team A" +| "Player B" | "Team A" +| "Player D" | "Team B" +| "Player E" | "Team C" +| "Player F" | "Team C" -2+d|Rows: 3 +2+d|Rows: 5 |=== -Note that no results are returned for `Player D`, `Player E`, and `Player F`, since they have no outgoing `FRIEND_OF` relationships connected to them. +Note that no results are returned for `Player C`, since they are not connected to any `Team` with a `PLAYS_FOR` relationship. .Query using regular `OPTIONAL CALL` [source, cypher] ---- MATCH (p:Player) OPTIONAL CALL (p) { - MATCH (p)-[:FRIEND_OF]->(friend:Player) - RETURN friend + MATCH (p)-[:PLAYS_FOR]->(team:Team) + RETURN team } -RETURN p.name AS playerName, count(friend) AS numberOfFriends -ORDER BY numberOfFriends +RETURN p.name AS playerName, team.name AS team ---- -Now, all `Player` nodes, regardless of whether they have any friends or not, are returned. -(Those without any outgoing `FRIEND_OF` relationships are returned with the result `0` because `count()` ignores `null` values.) +Now all `Player` nodes, regardless of whether they have any `PLAYS_FOR` relationships connected to a `Team`, are returned. +.Result .Result [role="queryresult",options="header,footer",cols="2*m"] |=== -| playerName | numberOfFriends +| playerName | team -| "Player D" | 0 -| "Player E" | 0 -| "Player F" | 0 -| "Player B" | 1 -| "Player C" | 1 -| "Player A" | 2 +| "Player A" | "Team A" +| "Player B" | "Team A" +| "Player C" | NULL +| "Player D" | "Team B" +| "Player E" | "Team C" +| "Player F" | "Team C" 2+d|Rows: 6 |=== @@ -495,8 +489,8 @@ Now, all `Player` nodes, regardless of whether they have any friends or not, are [[call-execution-order]] == Execution order of CALL subqueries -The order in which subqueries are executed is not defined. -If a query result depends on the order of execution of subqueries, an `ORDER BY` clause should precede the `CALL` clause. +The order in which rows from the outer scope are passed into subqueries is not defined. +If the results of the subquery depend on the order of these rows, use an `ORDER BY` clause before the `CALL` clause to guarantee a specific processing order for the rows. .Ordering results before `CALL` subquery ==== @@ -590,13 +584,13 @@ UNION ORDER BY p.age DESC LIMIT 1 } -RETURN p.name AS name, p.age AS age +RETURN p.name AS playerName, p.age AS age ---- .Result [role="queryresult",options="header,footer",cols="2*(p2:Player) - RETURN p2.name AS friend + MATCH (p)-[:PLAYS_FOR]->(team:Team) + RETURN team.name AS team } -RETURN p.name AS player, friend +RETURN p.name AS playerName, team ---- .Result -[role="queryresult",options="header,footer",cols="2* Date: Tue, 15 Oct 2024 07:49:29 +0100 Subject: [PATCH 46/64] Deprecate `existingDataSeedInstance` option to CREATE DATABASE (#1047) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace with new option `existingDataSeedServer` Documenting https://github.com/neo-technology/neo4j/pull/27123 --------- Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- ...ions-additions-removals-compatibility.adoc | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index 2aef91c68..d5442a8ab 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -16,6 +16,45 @@ New features are added to the language continuously, and occasionally, some feat This section lists all of the features that have been removed, deprecated, added, or extended in different Cypher versions. Replacement syntax for deprecated and removed features are also indicated. +[[cypher-deprecations-additions-removals-5.25]] +== Neo4j 5.25 + +=== Deprecated features + +[cols="2", options="header"] +|=== +| Feature +| Details + +a| +label:functionality[] +label:deprecated[] +[source, cypher, role="noheader"] +---- +CREATE DATABASE db OPTIONS { existingDataSeedInstance: ... } +---- +| The `CREATE DATABASE` option `existingDataSeedInstance` has been deprecated and replaced with the option link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/standard-databases/create-database/#manage-databases-create-database-options[`existingDataSeedServer`]. The functionality is unchanged. +|=== + +=== New features + +[cols="2", options="header"] +|=== +| Feature +| Details + +a| +label:functionality[] +label:new[] +[source, cypher, role="noheader"] +---- +CREATE DATABASE db OPTIONS { existingDataSeedServer: ... } +---- +| The option link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/standard-databases/create-database/#manage-databases-create-database-options[`existingDataSeedServer`] has been added to `CREATE DATABASE`. The functionality is the same as the deprecated option `existingDataSeedServer`, which this replaces. +|=== + + + [[cypher-deprecations-additions-removals-5.24]] == Neo4j 5.24 From c0be0b4157761889b45b93c058d7fae55c56169f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 08:53:25 +0200 Subject: [PATCH 47/64] Bump express from 4.21.0 to 4.21.1 in the dev-dependencies group (#1061) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the dev-dependencies group with 1 update: [express](https://github.com/expressjs/express). Updates `express` from 4.21.0 to 4.21.1
Release notes

Sourced from express's releases.

4.21.1

What's Changed

Full Changelog: https://github.com/expressjs/express/compare/4.21.0...4.21.1

Changelog

Sourced from express's changelog.

4.21.1 / 2024-10-08

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=express&package-manager=npm_and_yarn&previous-version=4.21.0&new-version=4.21.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- package-lock.json | 30 +++++++++++++++--------------- package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb8fd9d50..7111aee2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "asciidoctor-kroki": "^0.18.1" }, "devDependencies": { - "express": "^4.21.0", + "express": "^4.21.1", "nodemon": "^3.1.7" } }, @@ -760,9 +760,9 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, "engines": { "node": ">= 0.6" @@ -933,9 +933,9 @@ } }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, "dependencies": { "accepts": "~1.3.8", @@ -943,7 +943,7 @@ "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -3110,9 +3110,9 @@ } }, "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true }, "cookie-signature": { @@ -3234,9 +3234,9 @@ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, "express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, "requires": { "accepts": "~1.3.8", @@ -3244,7 +3244,7 @@ "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", diff --git a/package.json b/package.json index 6fa63e771..527fcd494 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "asciidoctor-kroki": "^0.18.1" }, "devDependencies": { - "express": "^4.21.0", + "express": "^4.21.1", "nodemon": "^3.1.7" }, "overrides": { From 942baaba5d423daca860e3566316604373013374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:11:38 +0200 Subject: [PATCH 48/64] clarify point.distance function (#1064) --- .../pages/appendix/gql-conformance/additional-cypher.adoc | 4 +++- modules/ROOT/pages/functions/index.adoc | 4 +++- modules/ROOT/pages/functions/spatial.adoc | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc b/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc index 2a33e5d4c..166c50e57 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc @@ -301,7 +301,9 @@ Either the pattern already exists, or it needs to be created. | Returns a 2D or 3D point object, given two or respectively three coordinate values in the Cartesian coordinate system or WGS 84 geographic coordinate system. | xref:functions/spatial.adoc#functions-point-distance[`point.distance()`] -| Returns a `FLOAT` representing the geodesic distance between any two points in the same CRS. +| Returns a `FLOAT` representing the distance between any two points in the same CRS. +If the points are in the WGS 84 CRS, the function returns the geodesic distance (i.e., the shortest path along the curved surface of the Earth). +If the points are in a Cartesian CRS, the function returns the Euclidean distance (i.e., the shortest straight-line distance in a flat, planar space). | xref:functions/spatial.adoc#functions-point-withinBBox[`point.withinBBox()`] | Returns true if the provided point is within the bounding box defined by the two provided points. diff --git a/modules/ROOT/pages/functions/index.adoc b/modules/ROOT/pages/functions/index.adoc index 315171f5c..d10e1c1ef 100644 --- a/modules/ROOT/pages/functions/index.adoc +++ b/modules/ROOT/pages/functions/index.adoc @@ -573,7 +573,9 @@ These functions are used to specify 2D or 3D points in a geographic or cartesian 1.1+| xref::functions/spatial.adoc#functions-distance[`point.distance()`] | `point.distance(from :: POINT, to :: POINT) :: FLOAT` -| Returns a `FLOAT` representing the geodesic distance between any two points in the same CRS. +| Returns a `FLOAT` representing the distance between any two points in the same CRS. +If the points are in the WGS 84 CRS, the function returns the geodesic distance (i.e., the shortest path along the curved surface of the Earth). +If the points are in a Cartesian CRS, the function returns the Euclidean distance (i.e., the shortest straight-line distance in a flat, planar space). 1.1+| xref::functions/spatial.adoc#functions-withinBBox[`point.withinBBox()`] | `point.withinBBox(point :: POINT, lowerLeft :: POINT, upperRight :: POINT) :: BOOLEAN` diff --git a/modules/ROOT/pages/functions/spatial.adoc b/modules/ROOT/pages/functions/spatial.adoc index 83686c2d0..e83511990 100644 --- a/modules/ROOT/pages/functions/spatial.adoc +++ b/modules/ROOT/pages/functions/spatial.adoc @@ -250,7 +250,9 @@ If `null` is provided as the argument, `null` is returned. .Details |=== | *Syntax* 3+| `point.distance(from, to)` -| *Description* 3+| Returns a `FLOAT` representing the geodesic distance between any two points in the same CRS. +| *Description* 3+| Returns a `FLOAT` representing the distance between any two points in the same CRS. +If the points are in the WGS 84 CRS, the function returns the geodesic distance (i.e., the shortest path along the curved surface of the Earth). +If the points are in a Cartesian CRS, the function returns the Euclidean distance (i.e., the shortest straight-line distance in a flat, planar space). .3+| *Arguments* | *Name* | *Type* | *Description* | `from` | `POINT` | A start point. | `to` | `POINT` | An end point in the same CRS as the start point. From 42f14576aaded5f0591226523d11f9f306105931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:23:45 +0200 Subject: [PATCH 49/64] fix functions table (Logarithmic was missing) (#1065) --- modules/ROOT/pages/functions/index.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/pages/functions/index.adoc b/modules/ROOT/pages/functions/index.adoc index d10e1c1ef..bb324d520 100644 --- a/modules/ROOT/pages/functions/index.adoc +++ b/modules/ROOT/pages/functions/index.adoc @@ -208,7 +208,7 @@ LOAD CSV functions can be used to get information about the file that is process [[header-query-functions-logarithmic]] -**xref::functions/mathematical-logarithmic.adoc[Logarithmic functions]** +== Logarithmic functions These functions all operate on numerical expressions only, and will return an error if used on any other values. From ab80e086391779440928e4f7ddd68a4c904652e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:46:35 +0200 Subject: [PATCH 50/64] Restructure Constraints section (#1041) Cheat sheet PR: https://github.com/neo4j/docs-cheat-sheet/pull/196 Ops Manual PR: https://github.com/neo4j/docs-operations/pull/1874 --------- Co-authored-by: Therese Magnusson --- modules/ROOT/content-nav.adoc | 2 +- .../gql-conformance/additional-cypher.adoc | 28 +- modules/ROOT/pages/clauses/load-csv.adoc | 6 +- modules/ROOT/pages/clauses/merge.adoc | 4 +- .../ROOT/pages/clauses/optional-match.adoc | 2 +- modules/ROOT/pages/constraints/examples.adoc | 2939 ----------------- modules/ROOT/pages/constraints/index.adoc | 126 +- .../constraints/managing-constraints.adoc | 1826 ++++++++++ modules/ROOT/pages/constraints/syntax.adoc | 273 +- ...ions-additions-removals-compatibility.adoc | 12 +- .../managing-indexes.adoc | 12 +- .../using-indexes.adoc | 18 +- .../ROOT/pages/introduction/cypher-neo4j.adoc | 14 +- .../pages/introduction/cypher-overview.adoc | 2 +- .../ROOT/pages/patterns/shortest-paths.adoc | 2 +- .../property-structural-constructed.adoc | 4 +- 16 files changed, 1964 insertions(+), 3306 deletions(-) delete mode 100644 modules/ROOT/pages/constraints/examples.adoc create mode 100644 modules/ROOT/pages/constraints/managing-constraints.adoc diff --git a/modules/ROOT/content-nav.adoc b/modules/ROOT/content-nav.adoc index 2eabb7c4c..35d451b4d 100644 --- a/modules/ROOT/content-nav.adoc +++ b/modules/ROOT/content-nav.adoc @@ -94,8 +94,8 @@ ** xref:indexes/syntax.adoc[] * xref:constraints/index.adoc[] +** xref:constraints/managing-constraints.adoc[] ** xref:constraints/syntax.adoc[] -** xref:constraints/examples.adoc[] * xref:planning-and-tuning/index.adoc[] ** xref:planning-and-tuning/execution-plans.adoc[] diff --git a/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc b/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc index 166c50e57..46134dceb 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc @@ -509,29 +509,17 @@ GQL supports `GRAPH TYPES` as a way of constraining a graph schema, but does not | Cypher feature | Description -| xref:constraints/examples.adoc#constraints-examples-node-uniqueness[Node property uniqueness constraints] -| Ensures that certain nodes have a set of specified properties whose combined value is unique when all properties exist on the node +| xref:constraints/managing-constraints.adoc#create-property-uniqueness-constraints[Property uniqueness constraints] +| Ensures that the combined property values are unique for all nodes with a specific label or all relationships with a specific type. -| xref:constraints/examples.adoc#constraints-examples-relationship-uniqueness[Relationship property uniqueness constraints] -| Ensures that certain relationships have a set of specified properties whose combined value is unique when all properties exist on the relationship. +| xref:constraints/managing-constraints.adoc#create-property-existence-constraints[Property existence constraints] +| Ensures that a property exists either for all nodes with a specific label or for all relationships with a specific type. -| xref:constraints/examples.adoc#constraints-examples-node-property-existence[Node property existence constraints] -| Ensures that certain nodes have a specified property. +| xref:constraints/managing-constraints.adoc#create-property-type-constraints[Property type constraints] +| Ensures that a property has the required property type for all nodes with a specific label or for all relationships with a specific type. -| xref:constraints/examples.adoc#constraints-examples-relationship-property-existence[Relationship property existence constraints] -| Ensures that certain relationships have a specified property. - -| xref:constraints/examples.adoc#constraints-examples-node-property-type[Node property type constraints] -| Ensures that certain nodes have a property of the required property type when the property exists on the node. - -| xref:constraints/examples.adoc#constraints-examples-relationship-property-type[Relationship property type constraints] -| Ensures that certain relationships have a property of the required property type when the property exists on the relationship. - -| xref:constraints/examples.adoc#constraints-examples-node-key[Node key constraints] -| Ensures that certain nodes have a set of specified properties whose combined value is unique and all properties in the set are present. - -| xref:constraints/examples.adoc#constraints-examples-relationship-key[Relationship key constraints] -| Ensures that certain relationships have a set of defined properties whose combined value is unique. It also ensures that all properties in the set are present. +| xref:constraints/managing-constraints.adoc#create-key-constraints[Key constraints] +| Ensures that all properties exist and that the combined property values are unique for all nodes with a specific label or all relationships with a specific type. |=== diff --git a/modules/ROOT/pages/clauses/load-csv.adoc b/modules/ROOT/pages/clauses/load-csv.adoc index de374e266..fa5804f1b 100644 --- a/modules/ROOT/pages/clauses/load-csv.adoc +++ b/modules/ROOT/pages/clauses/load-csv.adoc @@ -601,12 +601,12 @@ For more `STRING` manipulation functions, see xref:functions/string.adoc[String == Recommendations -=== Create uniqueness constraints +=== Create property uniqueness constraints -Always create uniqueness xref:constraints/index.adoc[constraints] prior to importing data, to avoid duplicates or colliding entities. +Always create xref:constraints/managing-constraints.adoc#create-property-uniqueness-constraints[property uniqueness constraints] prior to importing data, to avoid duplicates or colliding entities. If the source file contains duplicated data and the right constraints are in place, Cypher raises an error. -.Create xref:constraints/examples.adoc#constraints-examples-node-uniqueness[node property uniqueness constraints] on person ID +.Create a node property uniqueness constraints on person ID ==== .persons.csv diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index 1b93c98d3..669409c6a 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -25,7 +25,7 @@ If partial matches are needed, this can be accomplished by splitting a pattern i [NOTE] ==== Under concurrent updates, `MERGE` only guarantees the existence of the `MERGE` pattern, but not uniqueness. -To guarantee uniqueness of nodes with certain properties, a xref::constraints/index.adoc[property uniqueness constraint] should be used. +To guarantee uniqueness of nodes with certain properties, a xref:constraints/managing-constraints.adoc#create-property-uniqueness-constraints[property uniqueness constraint] should be used. See xref::clauses/merge.adoc#query-merge-using-unique-constraints[Using property uniqueness constraints with `MERGE`]. ==== @@ -511,7 +511,7 @@ This is in contrast to the example shown above in xref::clauses/merge.adoc#merge [[query-merge-using-unique-constraints]] == Using node property uniqueness constraints with `MERGE` -Cypher prevents getting conflicting results from `MERGE` when using patterns that involve property uniqueness constraints. +Cypher prevents getting conflicting results from `MERGE` when using patterns that involve xref:constraints/managing-constraints.adoc#create-property-uniqueness-constraints[property uniqueness constraints]. In this case, there must be at most one node that matches that pattern. For example, given two property node uniqueness constraints on `:Person(id)` and `:Person(ssn)`, a query such as `MERGE (n:Person {id: 12, ssn: 437})` will fail, if there are two different nodes (one with `id` 12 and one with `ssn` 437), or if there is only one node with only one of the properties. diff --git a/modules/ROOT/pages/clauses/optional-match.adoc b/modules/ROOT/pages/clauses/optional-match.adoc index ac59b099c..44e2dba20 100644 --- a/modules/ROOT/pages/clauses/optional-match.adoc +++ b/modules/ROOT/pages/clauses/optional-match.adoc @@ -54,7 +54,7 @@ For example, the matching variables from one `MATCH` clause will provide the con However, there are two important differences between Neo4j and SQL which helps to explain `OPTIONAL MATCH` further. . While it is both possible and advised to enforce partial schemas using indexes and constraints, Neo4j offers a greater degree of schema flexibility than a relational database. -Nodes and relationships in a Neo4j database do not have to have a specific property set to them because other nodes or relationships in the same graph have that property (unless there is a existence constraint created on the specific property). +Nodes and relationships in a Neo4j database do not have to have a specific property set to them because other nodes or relationships in the same graph have that property (unless there is a xref:constraints/managing-constraints.adoc#create-property-existence-constraints[property existence constraint] created on the specific property). . Queries in Cypher are run as pipelines. If a clause returns no results, it will effectively end the query as subsequent clauses will have no data to execute upon. diff --git a/modules/ROOT/pages/constraints/examples.adoc b/modules/ROOT/pages/constraints/examples.adoc deleted file mode 100644 index e84df4470..000000000 --- a/modules/ROOT/pages/constraints/examples.adoc +++ /dev/null @@ -1,2939 +0,0 @@ -:description: Examples of how to manage constraints used for ensuring data integrity. -:page-toclevels: 1 -include::https://raw.githubusercontent.com/neo4j-graphacademy/courses/main/asciidoc/courses/cypher-indexes-constraints/ad.adoc[] - -[[constraints-examples]] -= Examples - -This page contains examples of how to manage constraints used for ensuring data integrity. - -[[constraints-examples-node-uniqueness]] -== Node property uniqueness constraints - -A node property uniqueness constraint ensures that certain nodes have a set of specified properties whose combined value is unique when all properties exist on the node. - -* xref::constraints/examples.adoc#constraints-create-a-node-uniqueness-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-node-uniqueness-constraint-by-param[] -* xref::constraints/examples.adoc#constraints-create-a-node-uniqueness-constraint-if-not-exist[] -* xref::constraints/examples.adoc#constraints-create-a-node-uniqueness-constraint-with-index-provider[] -* xref::constraints/examples.adoc#constraints-create-an-already-existing-node-uniqueness-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-node-uniqueness-constraint-on-same-schema-as-existing-index[] -* xref::constraints/examples.adoc#constraints-create-a-node-that-complies-with-a-uniqueness-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-node-that-violates-a-uniqueness-constraint[] -* xref::constraints/examples.adoc#constraints-fail-to-create-a-uniqueness-constraint-due-to-conflicting-nodes[] - - -[[constraints-create-a-node-uniqueness-constraint]] -=== Create a node property uniqueness constraint - -When creating a property uniqueness constraint, it is recommended to provide a constraint name. - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT book_isbn -FOR (book:Book) REQUIRE book.isbn IS UNIQUE ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -[NOTE] -==== -The detailed statistics view currently says `Unique constraints added: 1`. -It will be updated to say `Node property uniqueness constraints added: 1` in Neo4j 6.0. -==== - -====== - -[role=label--new-5.16] -[[constraints-create-a-node-uniqueness-constraint-by-param]] -=== Create a node property uniqueness constraint using a parameter - -The constraint name can also be given as a parameter. - -.+CREATE CONSTRAINT+ -====== - -.Parameters -[source, parameters] ----- -{ - "name": "node_uniqueness_param" -} ----- - -.Query -[source, cypher] ----- -CREATE CONSTRAINT $name -FOR (book:Book) REQUIRE book.prop1 IS UNIQUE ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -[NOTE] -==== -The detailed statistics view currently says `Unique constraints added: 1`. -It will be updated to say `Node property uniqueness constraints added: 1` in Neo4j 6.0. -==== - -====== - - -[[constraints-create-a-node-uniqueness-constraint-if-not-exist]] -=== Handling existing constraints when creating a constraint - -Creating an already existing constraint will fail. -To avoid such an error, `IF NOT EXISTS` can be added to the `CREATE` command. -This will ensure that no error is thrown and that no constraint is created if any other constraint with the given name, or another node property uniqueness constraint on the same schema, already exists. -As of Neo4j 5.17, an informational notification is instead returned showing the existing constraint which blocks the creation. - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT book_isbn2 IF NOT EXISTS -FOR (book:Book) REQUIRE book.isbn2 IS UNIQUE ----- - -Assuming no constraint with the given name or other node property uniqueness constraint on the same schema already exists, the query will return: - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -[NOTE] -==== -The detailed statistics view currently says `Unique constraints added: 1`. -It will be updated to say `Node property uniqueness constraints added: 1` in Neo4j 6.0. -==== - -====== - - -[[constraints-create-a-node-uniqueness-constraint-with-index-provider]] -=== Specifying an index provider when creating a constraint - -To create a property uniqueness constraint with a specific index provider for the backing index, the `OPTIONS` clause is used. - -The index type of the backing index is set with the `indexProvider` option. - -The only valid value for the index provider is: - -* `range-1.0` label:default[] - -// Only one valid value exists for the index provider in Neo4j 5.0 - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT constraint_with_options -FOR (book:Book) REQUIRE (book.prop1, book.prop2) IS UNIQUE -OPTIONS { - indexProvider: 'range-1.0' -} ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -[NOTE] -==== -The detailed statistics view currently says `Unique constraints added: 1`. -It will be updated to say `Node property uniqueness constraints added: 1` in Neo4j 6.0. -==== - -====== - -There is no valid index configuration values for the constraint-backing range indexes. - - -[[constraints-create-an-already-existing-node-uniqueness-constraint]] -=== Creating an already existing constraint will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a property uniqueness constraint on the property `published` on nodes with the `Book` label, when that constraint already exists: - -//// -[source, cypher, role=test-setup] ----- -CREATE CONSTRAINT preExisting_book_published FOR (book:Book) REQUIRE book.published IS UNIQUE ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT book_published FOR (book:Book) REQUIRE book.published IS UNIQUE ----- - -In this case, the constraint cannot be created because it already exists. - -.Error message -[source, error] ----- -Constraint already exists: -Constraint( id=4, name='preExisting_book_published', type='UNIQUENESS', schema=(:Book {published}), ownedIndex=3 ) ----- - -[NOTE] -==== -The constraint type will be updated to say `NODE PROPERTY UNIQUENESS` in Neo4j 6.0. -==== - -====== - - -[[constraints-create-a-node-uniqueness-constraint-on-same-schema-as-existing-index]] -=== Creating a constraint on the same schema as an existing index will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a property uniqueness constraint on the property `wordCount` on nodes with the `Book` label, when an index already exists on that label and property combination: - -//// -[source, cypher, role=test-setup] ----- -CREATE INDEX preExisting_book_word_count FOR (book:Book) ON (book.wordCount) ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT book_word_count FOR (book:Book) REQUIRE book.wordCount IS UNIQUE ----- - -In this case, the constraint cannot be created because there already exists an index covering that schema. - -.Error message -[source, error] ----- -There already exists an index (:Book {wordCount}). -A constraint cannot be created until the index has been dropped. ----- - -====== - - -[[constraints-create-a-node-that-complies-with-a-uniqueness-constraint]] -=== Creating a node that complies with an existing constraint - - -.+CREATE NODE+ -====== - -Create a `Book` node with an `isbn` that is not already in the graph: - -.Query -[source, cypher] ----- -CREATE (book:Book {isbn: '1449356265', title: 'Graph Databases'}) ----- - -.Result -[queryresult] ----- -Added 1 label, created 1 node, set 2 properties ----- - -====== - - -[[constraints-create-a-node-that-violates-a-uniqueness-constraint]] -=== Creating a node that violates an existing constraint will fail - - -.+CREATE NODE+ -====== - -Create a `Book` node with an `isbn` that is already used in the graph: - -.Query -[source, cypher, role=test-fail] ----- -CREATE (book:Book {isbn: '1449356265', title: 'Graph Databases'}) ----- - -In this case, the node is not created because the `isbn` property is in conflict with an existing constraint. - -.Error message -[source, error] ----- -Node(0) already exists with label `Book` and property `isbn` = '1449356265' ----- - -====== - - -[[constraints-fail-to-create-a-uniqueness-constraint-due-to-conflicting-nodes]] -=== Creating a constraint when there exist conflicting nodes will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a property uniqueness constraint on the property `title` on nodes with the `Book` label, when there are two nodes with the same `title`: - -//// -[source, cypher, role=test-setup] ----- -CREATE (book:Book {isbn: '9780393972832', title: 'Moby Dick'}); -CREATE (book:Book {isbn: '9780763630188', title: 'Moby Dick'}) ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT book_title FOR (book:Book) REQUIRE book.title IS UNIQUE ----- - -In this case, the constraint cannot be created because it is in conflict with the existing graph. -Either use xref:indexes/search-performance-indexes/managing-indexes.adoc[] instead, or remove/correct the offending nodes and then re-apply the constraint. - -.Error message -[source, error] ----- -Unable to create Constraint( name='book_title', type='UNIQUENESS', schema=(:Book {title}) ): -Both Node(0) and Node(1) have the label `Book` and property `title` = 'Moby Dick' ----- - -[NOTE] -==== -The constraint type will be updated to say `NODE PROPERTY UNIQUENESS` in Neo4j 6.0. -==== - -====== - -The constraint creation fails on the first offending nodes that are found. -This does not guarantee that there are no other offending nodes in the graph. -Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. - -This is an example `MATCH` query to find all offending nodes with the non-unique property values for the constraint above: - -.Query -[source, cypher] ----- -MATCH (book1:Book), (book2:Book) -WHERE book1.title = book2.title AND NOT book1 = book2 -RETURN book1, book2 ----- - -[role=label--new-5.7] -[[constraints-examples-relationship-uniqueness]] -== Relationship property uniqueness constraints - -A relationship property uniqueness constraint ensures that certain relationships have a set of specified properties whose combined value is unique when all properties exist on the relationship. - -* xref::constraints/examples.adoc#constraints-create-a-relationship-uniqueness-constraints[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-uniqueness-constraints-by-param[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-uniqueness-constraints-if-not-exist[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-uniqueness-constraints-with-index-provider[] -* xref::constraints/examples.adoc#constraints-create-an-already-existing-relationship-uniqueness-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-uniqueness-constraint-on-same-schema-as-existing-index[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-that-complies-with-a-uniqueness-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-that-violates-a-uniqueness-constraint[] -* xref::constraints/examples.adoc#constraints-fail-to-create-a-uniqueness-constraint-due-to-conflicting-relationships[] - - -[[constraints-create-a-relationship-uniqueness-constraints]] -=== Create a relationship property uniqueness constraint - -When creating a property uniqueness constraint, it is recommended to provide a constraint name. - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT sequels -FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.order, sequel.seriesTitle) IS UNIQUE ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -[NOTE] -==== -The detailed statistics view currently says `Relationship uniqueness constraints added: 1`. -It will be updated to say `Relationship property uniqueness constraints added: 1` in Neo4j 6.0. -==== - -====== - - -[role=label--new-5.16] -[[constraints-create-a-relationship-uniqueness-constraints-by-param]] -=== Create a relationship property uniqueness constraint using a parameter - -The constraint name can also be given as a parameter. - -.+CREATE CONSTRAINT+ -====== - -.Parameters -[source, parameters] ----- -{ - "name": "rel_uniqueness_param" -} ----- - -.Query -[source, cypher] ----- -CREATE CONSTRAINT $name -FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.prop1) IS UNIQUE ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -[NOTE] -==== -The detailed statistics view currently says `Relationship uniqueness constraints added: 1`. -It will be updated to say `Relationship property uniqueness constraints added: 1` in Neo4j 6.0. -==== - -====== - - -[[constraints-create-a-relationship-uniqueness-constraints-if-not-exist]] -=== Handling existing constraints when creating a constraint - -Creating an already existing constraint will fail. -To avoid such an error, `IF NOT EXISTS` can be added to the `CREATE` command. -This will ensure that no error is thrown and that no constraint is created if any other constraint with the given name, or another relationship property uniqueness constraint on the same schema, already exists. -As of Neo4j 5.17, an informational notification is instead returned showing the existing constraint which blocks the creation. - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT sequels IF NOT EXISTS -FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.order) IS UNIQUE ----- - -Assuming a constraint with the name `sequels` already exists: - -.Result -[queryresult] ----- -(no changes, no records) ----- - -.Notification -[source] ----- -`CREATE CONSTRAINT sequels IF NOT EXISTS FOR ()-[e:SEQUEL_OF]-() REQUIRE (e.order) IS UNIQUE` has no effect. -`CONSTRAINT sequels FOR ()-[e:SEQUEL_OF]-() REQUIRE (e.order, e.seriesTitle) IS UNIQUE` already exists. ----- - -[NOTE] -==== -The detailed statistics view currently says `Relationship uniqueness constraints added: 1`. -It will be updated to say `Relationship property uniqueness constraints added: 1` in Neo4j 6.0. -==== - -====== - - -[[constraints-create-a-relationship-uniqueness-constraints-with-index-provider]] -=== Specifying an index provider when creating a constraint - -To create a property uniqueness constraint with a specific index provider for the backing index, the `OPTIONS` clause is used. - -The index type of the backing index is set with the `indexProvider` option. - -The only valid value for the index provider is: - -* `range-1.0` label:default[] - -// Only one valid value exists for the index provider in Neo4j 5.0 - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT rel_constraint_with_options -FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.order, sequel.seriesTitle, sequel.number) IS UNIQUE -OPTIONS { - indexProvider: 'range-1.0' -} ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -[NOTE] -==== -The detailed statistics view currently says `Relationship uniqueness constraints added: 1`. -It will be updated to say `Relationship property uniqueness constraints added: 1` in Neo4j 6.0. -==== - -====== - -There are no valid index configuration values for the constraint-backing range indexes. - - -[[constraints-create-an-already-existing-relationship-uniqueness-constraint]] -=== Creating an already existing constraint will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a property uniqueness constraint on the properties `order` and `seriesTitle` on relationships with the `SEQUEL_OF` relationship type, when that constraint already exists: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT sequel_order_seriestitle FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.order, sequel.seriesTitle) IS UNIQUE ----- - -In this case, the constraint cannot be created because it already exists. - -.Error message -[source, error] ----- -Constraint already exists: -Constraint( id=13, name='sequels', type='RELATIONSHIP UNIQUENESS', schema=()-[:SEQUEL_OF {order, seriesTitle}]-(), ownedIndex=12 ) ----- - -[NOTE] -==== -The constraint type will be updated to say `RELATIONSHIP PROPERTY UNIQUENESS` in Neo4j 6.0. -==== - -====== - - -[[constraints-create-a-relationship-uniqueness-constraint-on-same-schema-as-existing-index]] -=== Creating a constraint on the same schema as an existing index will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a property uniqueness constraint on the property `order` on relationships with the `SEQUEL_OF` relationship type, when an index already exists on that relationship type and property combination: - -//// -[source, cypher, role=test-setup] ----- -CREATE INDEX sequel_order FOR ()-[sequel:SEQUEL_OF]-() ON (sequel.order) ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT sequel_series_title FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.order) IS UNIQUE ----- - -In this case, the constraint cannot be created because there already exists an index covering that schema. - -.Error message -[source, error] ----- -There already exists an index ()-[:SEQUEL_OF {order}]-(). -A constraint cannot be created until the index has been dropped. ----- - -====== - - -[[constraints-create-a-relationship-that-complies-with-a-uniqueness-constraint]] -=== Creating a relationship that complies with an existing constraint - - -.+CREATE RELATIONSHIP+ -====== - -Create a `SEQUEL_OF` relationship with values for properties `order` and `seriesTitle` that are not already in the graph: - -.Query -[source, cypher] ----- -CREATE (:Book {title: 'Spirit Walker'})-[:SEQUEL_OF {order: 1, seriesTitle: 'Chronicles of Ancient Darkness'}]->(:Book {title: 'Wolf Brother'}) ----- - -.Result -[queryresult] ----- -Added 2 labels, created 2 nodes, set 4 properties, created 1 relationship. ----- - -====== - - -[[constraints-create-a-relationship-that-violates-a-uniqueness-constraint]] -=== Creating a relationship that violates an existing constraint will fail - - -.+CREATE RELATIONSHIP+ -====== - -Create a `SEQUEL_OF` relationship with values for properties `order` and `seriesTitle` that are already used in the graph: - -.Query -[source, cypher, role=test-fail] ----- -MATCH (wolfBrother:Book {title: 'Wolf Brother'}), (spiritWalker:Book {title: 'Spirit Walker'}) -CREATE (spiritWalker)-[:SEQUEL_OF {order: 1, seriesTitle: 'Chronicles of Ancient Darkness'}]->(wolfBrother) ----- - -In this case, the relationship is not created because the combination of the `order` and `seriesTitle` properties are in conflict with an existing constraint. - -.Error message -[source, error] ----- -Relationship(0) already exists with type `SEQUEL_OF` and properties `order` = 1, `seriesTitle` = 'Chronicles of Ancient Darkness' ----- - -====== - - -[[constraints-fail-to-create-a-uniqueness-constraint-due-to-conflicting-relationships]] -=== Creating a constraint when there exist conflicting relationships will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a property uniqueness constraint on the property `seriesTitle` on relationships with the `SEQUEL_OF` relationship type, when two relationships with the same `seriesTitle` already exist: - -//// -[source, cypher, role=test-setup] ----- -MATCH (spiritWalker:Book {title: 'Spirit Walker'}) -CREATE (:Book {title: 'Soul Eater'})-[:SEQUEL_OF {order: 2, seriesTitle: 'Chronicles of Ancient Darkness'}]->(spiritWalker) ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT series_title FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.seriesTitle) IS UNIQUE ----- - -In this case, the constraint cannot be created because it is in conflict with the existing graph. -Either use xref:indexes/search-performance-indexes/managing-indexes.adoc[] instead, or remove/correct the offending relationships and then re-apply the constraint. - -.Error message -[source, error] ----- -Unable to create Constraint( name='series_title', type='RELATIONSHIP UNIQUENESS', schema=()-[:SEQUEL_OF {seriesTitle}]-() ): -Both Relationship(0) and Relationship(1) have the type `SEQUEL_OF` and property `seriesTitle` = 'Chronicles of Ancient Darkness' ----- - -====== - -The constraint creation fails on the first offending relationships that are found. -This does not guarantee that there are no other offending relationships in the graph. -Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. - -This is an example `MATCH` query to find all offending relationships for the constraint above: - -.Query -[source, cypher] ----- -MATCH ()-[knows1:KNOWS]->(), ()-[knows2:KNOWS]->() -WHERE knows1.level = knows2.level AND NOT knows1 = knows2 -RETURN knows1, knows2 ----- - - -[role=label--enterprise-edition] -[[constraints-examples-node-property-existence]] -== Node property existence constraints - -A node property existence constraint ensures that certain nodes have a specified property. - -* xref::constraints/examples.adoc#constraints-create-a-node-property-existence-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-node-property-existence-constraint-by-param[] -* xref::constraints/examples.adoc#constraints-create-a-node-property-existence-constraint-if-not-exist[] -* xref::constraints/examples.adoc#constraints-create-an-already-existing-node-property-existence-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-node-that-complies-with-a-property-existence-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-node-that-violates-a-property-existence-constraint[] -* xref::constraints/examples.adoc#constraints-removing-an-existence-constrained-node-property[] -* xref::constraints/examples.adoc#constraints-fail-to-create-a-property-existence-constraint-due-to-existing-node[] - - -[[constraints-create-a-node-property-existence-constraint]] -=== Create a node property existence constraint - -When creating a node property existence constraint, it is recommended to provide a constraint name. - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT author_name -FOR (author:Author) REQUIRE author.name IS NOT NULL ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -[NOTE] -==== -The detailed statistics view for property existence constraints, `Property existence constraints added: 1`, will be split between nodes and relationships in Neo4j 6.0. -For the node property existence constraints, they will say `Node property existence constraints added: 1`. -==== - -====== - - -[role=label--new-5.16] -[[constraints-create-a-node-property-existence-constraint-by-param]] -=== Create a node property existence constraint using a parameter - -The constraint name can also be given as a parameter. - -.+CREATE CONSTRAINT+ -====== - -.Parameters -[source, parameters] ----- -{ - "name": "node_exist_param" -} ----- - -.Query -[source, cypher] ----- -CREATE CONSTRAINT $name -FOR (author:Author) REQUIRE author.surname IS NOT NULL ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -[NOTE] -==== -The detailed statistics view for property existence constraints, `Property existence constraints added: 1`, will be split between nodes and relationships in Neo4j 6.0. -For the node property existence constraints, they will say `Node property existence constraints added: 1`. -==== - -====== - - -[[constraints-create-a-node-property-existence-constraint-if-not-exist]] -=== Handling existing constraints when creating a constraint - -Creating an already existing constraint will fail. -To avoid such an error, `IF NOT EXISTS` can be added to the `CREATE` command. -This will ensure that no error is thrown and that no constraint is created if any other constraint with the given name, or another node property existence constraint on the same schema, already exists. -As of Neo4j 5.17, an informational notification is instead returned showing the existing constraint which blocks the creation. - -.+CREATE CONSTRAINT+ -====== - -//// -[source, cypher, role=test-setup] ----- -CREATE CONSTRAINT author_pseudonym -FOR (author:Author) REQUIRE author.pseudonym IS UNIQUE ----- -//// - -.Query -[source, cypher] ----- -CREATE CONSTRAINT author_pseudonym IF NOT EXISTS -FOR (author:Author) REQUIRE author.pseudonym IS NOT NULL ----- - -Assuming a constraint with the name `author_pseudonym` already exists: - -.Result -[queryresult] ----- -(no changes, no records) ----- - -.Notification -[source] ----- -`CREATE CONSTRAINT author_pseudonym IF NOT EXISTS FOR (e:Author) REQUIRE (e.pseudonym) IS NOT NULL` has no effect. -`CONSTRAINT author_pseudonym FOR (e:Author) REQUIRE (e.pseudonym) IS UNIQUE` already exists. ----- - -====== - - -[[constraints-create-an-already-existing-node-property-existence-constraint]] -=== Creating an already existing constraint will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a node property existence constraint on the property `name` on nodes with the `Author` label, when that constraint already exists: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT author_name -FOR (author:Author) REQUIRE author.name IS NOT NULL ----- - -In this case, the constraint cannot be created because it already exists. - -.Error message -[source, error] ----- -An equivalent constraint already exists, 'Constraint( id=10, name='author_name', type='NODE PROPERTY EXISTENCE', schema=(:Author {name}) )'. ----- - -====== - - -[[constraints-create-a-node-that-complies-with-a-property-existence-constraint]] -=== Creating a node that complies with an existing constraint - - -.+CREATE NODE+ -====== - -Create an `Author` node with a `name` property: - -.Query -[source, cypher] ----- -CREATE (author:Author {name:'Virginia Woolf', surname: 'Woolf'}) ----- - -.Result -[queryresult] ----- -Added 1 label, created 1 node, set 2 properties ----- - -====== - - -[[constraints-create-a-node-that-violates-a-property-existence-constraint]] -=== Creating a node that violates an existing constraint will fail - - -.+CREATE NODE+ -====== - -Create an `Author` node without a `name` property, given a property existence constraint on `:Author(name)`: - -.Query -[source, cypher, role=test-fail] ----- -CREATE (author:Author {surname: 'Austen'}) ----- - -In this case, the node is not created because it is missing the `name` property which is in conflict with an existing constraint. - -.Error message -[source, error] ----- -Node(0) with label `Author` must have the property `name` ----- - -====== - - -[[constraints-removing-an-existence-constrained-node-property]] -=== Removing an existence constrained node property will fail - - -.+REMOVE PROPERTY+ -====== - -Remove the `name` property from an existing node `Author`, given a property existence constraint on `:Author(name)`: - -.Query -[source, cypher, role=test-fail] ----- -MATCH (author:Author {name: 'Virginia Woolf'}) -REMOVE author.name ----- - -In this case, the property is not removed because it is in conflict with an existing constraint. - -.Error message -[source, error] ----- -Node(0) with label `Author` must have the property `name` ----- - -====== - - -[[constraints-fail-to-create-a-property-existence-constraint-due-to-existing-node]] -=== Creating a constraint when there exist conflicting nodes will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a constraint on the property `nationality` on nodes with the `Author` label, when there already exists a node without a `nationality` property: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT author_nationality FOR (author:Author) REQUIRE author.nationality IS NOT NULL ----- - -In this case, the constraint cannot be created because it is in conflict with the existing graph. -Remove or correct the offending nodes and then re-apply the constraint. - -.Error message -[source, error] ----- -Unable to create Constraint( type='NODE PROPERTY EXISTENCE', schema=(:Author {nationality}) ): -Node(0) with label `Author` must have the property `nationality` ----- - -====== - -The constraint creation fails on the first offending node that is found. -This does not guarantee that there are no other offending nodes in the graph. -Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. - -This is an example `MATCH` query to find all offending nodes missing the property for the constraint above: - -.Query -[source, cypher] ----- -MATCH (author:Author) -WHERE author.nationality IS NULL -RETURN author ----- - - -[role=label--enterprise-edition] -[[constraints-examples-relationship-property-existence]] -== Relationship property existence constraints - -A relationship property existence constraint ensures that certain relationships have a certain property. - -* xref::constraints/examples.adoc#constraints-create-a-relationship-property-existence-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-property-existence-constraint-by-param[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-property-existence-constraint-if-not-exist[] -* xref::constraints/examples.adoc#constraints-create-an-already-existing-relationship-property-existence-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-that-complies-with-a-property-existence-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-that-violates-a-property-existence-constraint[] -* xref::constraints/examples.adoc#constraints-removing-an-existence-constrained-relationship-property[] -* xref::constraints/examples.adoc#constraints-fail-to-create-a-property-existence-constraint-due-to-existing-relationship[] - - -[[constraints-create-a-relationship-property-existence-constraint]] -=== Create a relationship property existence constraint - -When creating a relationship property existence constraint, it is recommended to provide a constraint name. - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT wrote_year -FOR ()-[wrote:WROTE]-() REQUIRE wrote.year IS NOT NULL ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -[NOTE] -==== -The detailed statistics view for property existence constraints, `Property existence constraints added: 1`, will be split between nodes and relationships in Neo4j 6.0. -For the relationship property existence constraints, they will say `Relationship property existence constraints added: 1`. -==== - -====== - -[role=label--new-5.16] -[[constraints-create-a-relationship-property-existence-constraint-by-param]] -=== Create a relationship property existence constraint using a parameter - -The constraint name can also be given as a parameter. - -.+CREATE CONSTRAINT+ -====== - -.Parameters -[source, parameters] ----- -{ - "name": "rel_exist_param" -} ----- - -.Query -[source, cypher] ----- -CREATE CONSTRAINT $name -FOR ()-[wrote:WROTE]-() REQUIRE wrote.published IS NOT NULL ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -[NOTE] -==== -The detailed statistics view for property existence constraints, `Property existence constraints added: 1`, will be split between nodes and relationships in Neo4j 6.0. -For the relationship property existence constraints, they will say `Relationship property existence constraints added: 1`. -==== - -====== - - -[[constraints-create-a-relationship-property-existence-constraint-if-not-exist]] -=== Handling existing constraints when creating a constraint - -Creating an already existing constraint will fail. -To avoid such an error, `IF NOT EXISTS` can be added to the `CREATE` command. -This will ensure that no error is thrown and that no constraint is created if any other constraint with the given name, or another relationship property existence constraint on the same schema, already exists. -As of Neo4j 5.17, an informational notification is instead returned showing the existing constraint which blocks the creation. - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT wrote_year IF NOT EXISTS -FOR ()-[wrote:WROTE]-() REQUIRE wrote.year IS NOT NULL ----- - -Assuming that such a constraint already exists: - -.Result -[queryresult] ----- -(no changes, no records) ----- - -.Notification -[source] ----- -`CREATE CONSTRAINT wrote_year IF NOT EXISTS FOR ()-[e:WROTE]-() REQUIRE (e.year) IS NOT NULL` has no effect. -`CONSTRAINT wrote_year FOR ()-[e:WROTE]-() REQUIRE (e.year) IS NOT NULL` already exists. ----- - -====== - - -[[constraints-create-an-already-existing-relationship-property-existence-constraint]] -=== Creating an already existing constraint will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a named relationship property existence constraint on the property `locations` on relationships with the `WROTE` relationship type, when a constraint with the given name already exists: - -//// -[source, cypher, role=test-setup] ----- -CREATE CONSTRAINT wrote_locations FOR ()-[wrote:WROTE]-() REQUIRE wrote.location IS NOT NULL ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT wrote_locations -FOR ()-[wrote:WROTE]-() REQUIRE wrote.locations IS NOT NULL ----- - -In this case, the constraint cannot be created because there already exists a constraint with the given name. - -.Error message -[source, error] ----- -There already exists a constraint called 'wrote_locations'. ----- - -====== - - -[[constraints-create-a-relationship-that-complies-with-a-property-existence-constraint]] -=== Creating a relationship that complies with an existing constraint - - -.+CREATE RELATIONSHIP+ -====== - -Create a `WROTE` relationship with a `year` and `location` property, given property existence constraints on `:WROTE(year)` and `:WROTE(location)`: - -.Query -[source, cypher] ----- -CREATE (author:Author {name: 'Emily Brontë', surname: 'Brontë'})-[wrote:WROTE {year: 1847, location: 'Haworth, United Kingdom', published: true}]->(book:Book {title:'Wuthering Heights', isbn: 9789186579296}) ----- - -.Result -[queryresult] ----- -Added 2 labels, created 2 nodes, set 7 properties, created 1 relationship ----- - -====== - - -[[constraints-create-a-relationship-that-violates-a-property-existence-constraint]] -=== Creating a relationship that violates an existing constraint will fail - - -.+CREATE RELATIONSHIP+ -====== - -Create a `WROTE` relationship without a `location` property, given a property existence constraint `:WROTE(location)`: - -.Query -[source, cypher, role=test-fail] ----- -CREATE (author:Author {name: 'Charlotte Brontë', surname: 'Brontë'})-[wrote:WROTE {year: 1847, published: true}]->(book:Book {title: 'Jane Eyre', isbn:9780194241762}) ----- - -In this case, the relationship is not created because it is missing the `location` property which is in conflict with an existing constraint. - -.Error message -[source, error] ----- -Relationship(0) with type `WROTE` must have the property `location` ----- - -====== - - -[[constraints-removing-an-existence-constrained-relationship-property]] -=== Removing an existence constrained relationship property will fail - - -.+REMOVE PROPERTY+ -====== - -Remove the `location` property from an existing relationship of relationship type `WROTE`, given a property existence constraint `:WROTE(location)`: - -.Query -[source, cypher, role=test-fail] ----- -MATCH (author:Author)-[wrote:WROTE]->(book:Book) REMOVE wrote.location ----- - -In this case, the property is not removed because it is in conflict with an existing constraint. - -.Error message -[source, error] ----- -Relationship(0) with type `WROTE` must have the property `location` ----- - -====== - - -[[constraints-fail-to-create-a-property-existence-constraint-due-to-existing-relationship]] -=== Creating a constraint when there exist conflicting relationships will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a constraint on the property `language` on relationships with the `WROTE` relationship type, when there already exists a relationship without a property named `language`: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT wrote_language FOR ()-[wrote:WROTE]-() REQUIRE wrote.language IS NOT NULL ----- - -In this case, the constraint cannot be created because it is in conflict with the existing graph. -Remove or correct the offending relationships and then re-apply the constraint. - -.Error message -[source, error] ----- -Unable to create Constraint( type='RELATIONSHIP PROPERTY EXISTENCE', schema=()-[:WROTE {language}]-() ): -Relationship(0) with type `WROTE` must have the property `language` ----- - -====== - -The constraint creation fails on the first offending relationship that is found. -This does not guarantee that there are no other offending relationships in the graph. -Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. - -This is an example `MATCH` query to find all offending relationships missing the property for the constraint above: - -.Query -[source, cypher] ----- -MATCH ()-[wrote:WROTE]-() -WHERE wrote.language IS NULL -RETURN wrote ----- - - -[role=label--enterprise-edition label--new-5.9] -[[constraints-examples-node-property-type]] -== Node property type constraints - -A node property type constraint ensures that certain nodes have a property of the required property type when the property exists on the node. - -The allowed property types for the constraints are: - -* `BOOLEAN` -* `STRING` -* `INTEGER` -* `FLOAT` -* `DATE` -* `LOCAL TIME` -* `ZONED TIME` -* `LOCAL DATETIME` -* `ZONED DATETIME` -* `DURATION` -* `POINT` -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* Any closed dynamic union of the above types, e.g. `INTEGER | FLOAT | STRING`. label:new[Introduced in 5.11] - -For a complete reference describing all types available in Cypher, see the section on xref::values-and-types/property-structural-constructed.adoc#types-synonyms[types and their synonyms]. - -* xref::constraints/examples.adoc#constraints-create-a-node-property-type-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-node-property-type-constraint-by-param[] -* xref::constraints/examples.adoc#constraints-create-a-node-property-type-constraint-if-not-exist[] -* xref::constraints/examples.adoc#constraints-create-an-already-existing-node-property-type-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-different-than-existing-node-property-type-constraint[] -* xref::constraints/examples.adoc#constraints-create-node-property-type-constraints-on-invalid-types[] -* xref::constraints/examples.adoc#constraints-create-a-node-that-complies-with-a-property-type-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-node-that-violates-a-property-type-constraint[] -* xref::constraints/examples.adoc#constraints-fail-to-create-a-property-type-constraint-due-to-existing-node[] - - -[[constraints-create-a-node-property-type-constraint]] -=== Create a node property type constraint - -When creating a node property type constraint, it is recommended to provide a constraint name. - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT movie_title -FOR (movie:Movie) REQUIRE movie.title IS :: STRING ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - -[role=label--new-5.16] -[[constraints-create-a-node-property-type-constraint-by-param]] -=== Create a node property type constraint using a parameter - -The constraint name can also be given as a parameter. - -.+CREATE CONSTRAINT+ -====== - -.Parameters -[source, parameters] ----- -{ - "name": "node_prop_type_param" -} ----- - -.Query -[source, cypher] ----- -CREATE CONSTRAINT $name -FOR (movie:Movie) REQUIRE movie.prop1 IS :: INT ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - - -[role=label--new-5.11] -[[constraints-create-a-node-property-type-constraint-union]] -=== Create a node property type constraint with a union type - -A closed dynamic union allows a node property to maintain some type flexibility whilst preventing unexpected values from being stored. - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT movie_tagline -FOR (movie:Movie) REQUIRE movie.tagline IS :: STRING | LIST ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - - -[[constraints-create-a-node-property-type-constraint-if-not-exist]] -=== Handling existing constraints when creating a constraint - -Creating an already existing constraint will fail. -To avoid such an error, `IF NOT EXISTS` can be added to the `CREATE` command. -This will ensure that no error is thrown and that no constraint is created if any other constraint with the given name, or another node property type constraint on the same schema and property type, already exists. -As of Neo4j 5.17, an informational notification is instead returned showing the existing constraint which blocks the creation. - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT movie_titles IF NOT EXISTS -FOR (movie:Movie) REQUIRE movie.title :: STRING ----- - -Assuming a node property type constraint on the label `Movie` which restricts the property `title` to `STRING` values already exists: - -.Result -[queryresult] ----- -(no changes, no records) ----- - -.Notification -[source] ----- -`CREATE CONSTRAINT movie_titles IF NOT EXISTS FOR (e:Movie) REQUIRE (e.title) IS :: STRING` has no effect. -`CONSTRAINT movie_title FOR (e:Movie) REQUIRE e.title IS :: STRING` already exists. ----- - -====== - - -[[constraints-create-an-already-existing-node-property-type-constraint]] -=== Creating an already existing constraint will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a node property type constraint restricting the property `title` to `STRING` values on nodes with the `Movie` label, when that constraint already exists: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT movies -FOR (movie:Movie) REQUIRE movie.title IS TYPED STRING ----- - -In this case, the constraint cannot be created because it already exists. - -.Error message -[source, error] ----- -Constraint already exists: Constraint( id=22, name='movie_title', type='NODE PROPERTY TYPE', schema=(:Movie {title}), propertyType=STRING ) ----- - -====== - - -[[constraints-create-a-different-than-existing-node-property-type-constraint]] -=== Creating a constraint when there is an existing constraint with a different property type will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a node property type constraint restricting the property `seriesOrder` to float values on nodes with the `Movie` label, when a node property type constraint restricting the property `seriesOrder` to integer values already exists: - -//// -[source, cypher, role=test-setup] ----- -CREATE CONSTRAINT seriesOrder -FOR (movie:Movie) REQUIRE movie.seriesOrder IS :: INTEGER ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT order -FOR (movie:Movie) REQUIRE movie.seriesOrder IS :: FLOAT ----- - -In this case, the constraint cannot be created because there exists a conflicting constraint. - -.Error message -[source, error] ----- -Constraint already exists: Constraint( id=23, name='seriesOrder', type='NODE PROPERTY TYPE', schema=(:Movie {seriesOrder}), propertyType=INTEGER ) ----- - -====== - - -[[constraints-create-node-property-type-constraints-on-invalid-types]] -=== Creating constraints on invalid types will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a node property type constraint restricting the property `imdbScore` to map values on nodes with the `Movie` label: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT score -FOR (movie:Movie) REQUIRE movie.imdbScore IS :: MAP ----- - -In this case, the constraint cannot be created because values of type `MAP` cannot be stored in properties and therefore are not permitted in property type constraints. - -.Error message -[source, error] ----- -Failed to create node property type constraint: Invalid property type `MAP`. ----- - -====== - -.+CREATE CONSTRAINT+ -====== - -Create a node property type constraint restricting the property `imdbScore` to list of nullable float values on nodes with the `Movie` label: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT score -FOR (movie:Movie) REQUIRE movie.imdbScore IS :: LIST ----- - -In this case, the constraint cannot be created because the inner type of list types cannot be nullable. -The correct type to use for the constraint is `LIST` because `null` values cannot be stored as part of a list. - -.Error message -[source, error] ----- -Failed to create node property type constraint: Invalid property type `LIST`. Lists cannot have nullable inner types. ----- - -====== - -.+CREATE CONSTRAINT+ -====== - -Create a node property type constraint restricting the property `imdbScore` to list of lists of float values on nodes with the `Movie` label: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT score -FOR (movie:Movie) REQUIRE movie.imdbScore IS :: LIST> ----- - -In this case, the constraint cannot be created because the inner type of list types cannot be other lists. - -.Error message -[source, error] ----- -Failed to create node property type constraint: Invalid property type `LIST>`. Lists cannot have lists as an inner type. ----- - -====== - - -[[constraints-create-a-node-that-complies-with-a-property-type-constraint]] -=== Creating a node that complies with an existing constraint - - -.+CREATE NODE+ -====== - -Create an `Movie` node with a `STRING` `title` property: - -.Query -[source, cypher] ----- -CREATE (movie:Movie {title:'Iron Man'}) ----- - -.Result -[queryresult] ----- -Added 1 label, created 1 node, set 1 properties ----- - -====== - - -[[constraints-create-a-node-that-violates-a-property-type-constraint]] -=== Creating a node that violates an existing constraint will fail - - -.+CREATE NODE+ -====== - -Create a `Movie` node with an integer `title` property, given a property type constraint on the label `Movie` restricting the `title` property to `STRING` values: - -.Query -[source, cypher, role=test-fail] ----- -CREATE (movie:Movie {title: 123}) ----- - -In this case, the node is not created because the `title` property is in conflict with an existing constraint. - -.Error message -[source, error] ----- -Node(0) with label `Movie` has property `title` of wrong type `Long`. Allowed types: STRING ----- - -====== - - -[[constraints-fail-to-create-a-property-type-constraint-due-to-existing-node]] -=== Creating a constraint when there exist conflicting nodes will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a constraint restricting the property `franchise` to `STRING` values on nodes with the `Movie` label, when there already exists a node with a `BOOLEAN` `franchise` property: - -//// -[source, cypher, role=test-setup] ----- -CREATE (movie:Movie {title:'Captain America: The First Avenger', franchise: true}) ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT movie_franchise FOR (movie:Movie) REQUIRE movie.franchise IS :: STRING ----- - -In this case, the constraint cannot be created because it is in conflict with the existing graph. -Remove or correct the offending nodes and then re-apply the constraint. - -.Error message -[source, error] ----- -Unable to create Constraint( name='movie_franchise', type='NODE PROPERTY TYPE', schema=(:Movie {franchise}), propertyType=STRING ): -Node(0) with label `Movie` has property `franchise` of wrong type `Boolean`. Allowed types: STRING ----- - -====== - -The constraint creation fails on the first offending node that is found. -This does not guarantee that there are no other offending nodes in the graph. -Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. - -This is an example `MATCH` query to find all offending nodes with the wrong property type for the constraint above: - -.Query -[source, cypher] ----- -MATCH (movie:Movie) -WHERE movie.franchise IS NOT :: STRING -RETURN movie ----- - - -[role=label--enterprise-edition label--new-5.9] -[[constraints-examples-relationship-property-type]] -== Relationship property type constraints - -A relationship property type constraint ensures that certain relationships have a property of the required property type when the property exists on the relationship. - -The allowed property types for the constraints is: - -* `BOOLEAN` -* `STRING` -* `INTEGER` -* `FLOAT` -* `DATE` -* `LOCAL TIME` -* `ZONED TIME` -* `LOCAL DATETIME` -* `ZONED DATETIME` -* `DURATION` -* `POINT` -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* Any closed dynamic union of the above types, e.g. `INTEGER | FLOAT | STRING`. label:new[Introduced in 5.11] - -For a complete reference describing all types available in Cypher, see the section on xref::values-and-types/property-structural-constructed.adoc#types-synonyms[types and their synonyms]. - -* xref::constraints/examples.adoc#constraints-create-a-relationship-property-type-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-property-type-constraint-by-param[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-property-type-constraint-if-not-exist[] -* xref::constraints/examples.adoc#constraints-create-an-already-existing-relationship-property-type-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-different-than-existing-relationship-property-type-constraint[] -* xref::constraints/examples.adoc#constraints-create-relationship-property-type-constraints-on-invalid-types[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-that-complies-with-a-property-type-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-that-violates-a-property-type-constraint[] -* xref::constraints/examples.adoc#constraints-fail-to-create-a-property-type-constraint-due-to-existing-relationship[] - - -[[constraints-create-a-relationship-property-type-constraint]] -=== Create a relationship property type constraint - -When creating a relationship property type constraint, it is recommended to provide a constraint name. - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT part_of -FOR ()-[part:PART_OF]-() REQUIRE part.order IS :: INTEGER ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - -[role=label--new-5.16] -[[constraints-create-a-relationship-property-type-constraint-by-param]] -=== Create a relationship property type constraint using a parameter - -The constraint name can also be given as a parameter. - -.+CREATE CONSTRAINT+ -====== - -.Parameters -[source, parameters] ----- -{ - "name": "rel_prop_type_param" -} ----- - -.Query -[source, cypher] ----- -CREATE CONSTRAINT $name -FOR ()-[part:PART_OF]-() REQUIRE part.prop1 IS :: FLOAT ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - -[role=label--new-5.11] -[[constraints-create-a-relationship-property-type-constraint-union]] -=== Create a relationship property type constraint with a union type - -A closed dynamic union allows a relationship property to maintain some type flexibility whilst preventing unexpected values from being stored. - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT part_of_tags -FOR ()-[part:PART_OF]-() REQUIRE part.tags IS :: STRING | LIST ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - -[[constraints-create-a-relationship-property-type-constraint-if-not-exist]] -=== Handling existing constraints when creating a constraint - -Creating an already existing constraint will fail. -To avoid such an error, `IF NOT EXISTS` can be added to the `CREATE` command. -This will ensure that no error is thrown and that no constraint is created if any other constraint with the given name, or another relationship property type constraint on the same schema and property type, already exists. -As of Neo4j 5.17, an informational notification is instead returned showing the existing constraint which blocks the creation. - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT part_of IF NOT EXISTS -FOR ()-[part:PART_OF]-() REQUIRE part.order IS TYPED INTEGER ----- - -Assuming that such a constraint already exists: - -.Result -[queryresult] ----- -(no changes, no records) ----- - -.Notification -[source] ----- -`CREATE CONSTRAINT part_of IF NOT EXISTS FOR ()-[e:PART_OF]-() REQUIRE (e.order) IS :: INTEGER` has no effect. -`CONSTRAINT part_of FOR ()-[e:PART_OF]-() REQUIRE (e.order) IS :: INTEGER` already exists. ----- - -====== - - -[[constraints-create-an-already-existing-relationship-property-type-constraint]] -=== Creating an already existing constraint will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a relationship property type constraint restricting the property `order` to integer values on relationships with the `PART_OF` relationship type, when that constraint already exists: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT belongs_to -FOR ()-[part:PART_OF]-() REQUIRE part.order :: INTEGER ----- - -In this case, the constraint cannot be created because it already exists (but with a different name). - -.Error message -[source, error] ----- -Constraint already exists: Constraint( id=24, name='part_of', type='RELATIONSHIP PROPERTY TYPE', schema=()-[:PART_OF {order}]-(), propertyType=INTEGER ) ----- - -====== - - -[[constraints-create-a-different-than-existing-relationship-property-type-constraint]] -=== Creating a constraint when there is an existing constraint with a different property type will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a relationship property type constraint restricting the property `order` to float values on relationships with the `PART_OF` relationship type, when a relationship property type constraint restricting the property `order` to integer values already exists: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT order -FOR ()-[part:PART_OF]-() REQUIRE part.order IS :: FLOAT ----- - -In this case, the constraint cannot be created because there exists a conflicting constraint. - -.Error message -[source, error] ----- -Constraint already exists: Constraint( id=24, name='part_of', type='RELATIONSHIP PROPERTY TYPE', schema=()-[:PART_OF {order}]-(), propertyType=INTEGER ) ----- - -====== - - -[[constraints-create-relationship-property-type-constraints-on-invalid-types]] -=== Creating constraints on invalid types will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a relationship property type constraint restricting the property `releaseOrder` to integer values excluding `null` on relationships with the `PART_OF` relationship type: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT score -FOR ()-[part:PART_OF]-() REQUIRE part.releaseOrder IS :: INTEGER NOT NULL ----- - -In this case, the constraint cannot be created because excluding `null` is not allowed in property type constraints. -To also ensure that the property exists (is not `null`), add an existence constraint on the property. - -.Error message -[source, error] ----- -Failed to create relationship property type constraint: Invalid property type `INTEGER NOT NULL`. ----- - -====== - -.+CREATE CONSTRAINT+ -====== - -Create a relationship property type constraint restricting the property `releaseOrder` to list of nullable integer values on relationships with the `PART_OF` relationship type: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT score -FOR ()-[part:PART_OF]-() REQUIRE part.releaseOrder IS :: LIST ----- - -In this case, the constraint cannot be created because the inner type of list types cannot be nullable. -The correct type to use for the constraint is `LIST` because `null` values cannot be stored as part of a list. - -.Error message -[source, error] ----- -Failed to create relationship property type constraint: Invalid property type `LIST`. Lists cannot have nullable inner types. ----- - -====== - -.+CREATE CONSTRAINT+ -====== - -Create a relationship property type constraint restricting the property `releaseOrder` to list of lists of integer values on relationships with the `PART_OF` relationship type: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT score -FOR ()-[part:PART_OF]-() REQUIRE part.releaseOrder IS :: LIST> ----- - -In this case, the constraint cannot be created because the inner type of list types cannot be other lists. - -.Error message -[source, error] ----- -Failed to create relationship property type constraint: Invalid property type `LIST>`. Lists cannot have lists as an inner type. ----- - -====== - - -[[constraints-create-a-relationship-that-complies-with-a-property-type-constraint]] -=== Creating a relationship that complies with an existing constraint - - -.+CREATE RELATIONSHIP+ -====== - -Create a `PART_OF` relationship with an integer `order` property: - -//// -[source, cypher, role=test-setup] ----- -CREATE (franchise:Franchise {name:'MCU'}) ----- -//// - -.Query -[source, cypher] ----- -MATCH (movie:Movie {title:'Iron Man'}), (franchise:Franchise {name:'MCU'}) -CREATE (movie)-[part:PART_OF {order: 3}]->(franchise) ----- - -.Result -[queryresult] ----- -Set 1 property, created 1 relationship ----- - -====== - - -[[constraints-create-a-relationship-that-violates-a-property-type-constraint]] -=== Creating a relationship that violates an existing constraint will fail - - -.+CREATE RELATIONSHIP+ -====== - -Create a `PART_OF` relationship with a `STRING` `order` property, given a property type constraint on the relationship type `PART_OF` restricting the `order` property to integer values: - -.Query -[source, cypher, role=test-fail] ----- -MATCH (movie:Movie {title:'Captain America: The First Avenger'}), (franchise:Franchise {name:'MCU'}) -CREATE (movie)-[part:PART_OF {order: '1'}]->(franchise) ----- - -In this case, the relationship is not created because the `order` property is in conflict with an existing constraint. - -.Error message -[source, error] ----- -Relationship(0) with type `PART_OF` has property `order` of wrong type `String`. Allowed types: INTEGER ----- - -====== - - -[[constraints-fail-to-create-a-property-type-constraint-due-to-existing-relationship]] -=== Creating a constraint when there exist conflicting relationships will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a constraint restricting the property `releaseOrder` to integer values on relationships with the `PART_OF` relationship type, when there already exists a relationship with a `STRING` `releaseOrder` property: - -//// -[source, cypher, role=test-setup] ----- -MATCH (movie:Movie {title:'Captain America: The First Avenger'}), (franchise:Franchise {name:'MCU'}) -CREATE (movie)-[part:PART_OF {order: 1, releaseOrder: '5'}]->(franchise) ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT release_order -FOR ()-[part:PART_OF]-() REQUIRE part.releaseOrder IS :: INTEGER ----- - -In this case, the constraint cannot be created because it is in conflict with the existing graph. -Remove or correct the offending relationships and then re-apply the constraint. - -.Error message -[source, error] ----- -Unable to create Constraint( name='release_order', type='RELATIONSHIP PROPERTY TYPE', schema=()-[:PART_OF {releaseOrder}]-(), propertyType=INTEGER ): -Relationship(0) with type `PART_OF` has property `releaseOrder` of wrong type `String`. Allowed types: INTEGER ----- - -====== - -The constraint creation fails on the first offending relationship that is found. -This does not guarantee that there are no other offending relationships in the graph. -Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. - -This is an example `MATCH` query to find all offending relationships with the wrong property type for the constraint above: - -.Query -[source, cypher] ----- -MATCH ()-[part:PART_OF]-() -WHERE part.releaseOrder IS NOT :: INTEGER -RETURN part ----- - - -[role=label--enterprise-edition] -[[constraints-examples-node-key]] -== Node key constraints - -A node key constraint ensures that certain nodes have a set of specified properties whose combined value is unique and all properties in the set are present. - -* xref::constraints/examples.adoc#constraints-create-a-node-key-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-node-key-constraint-by-param[] -* xref::constraints/examples.adoc#constraints-create-a-node-key-constraint-if-not-exist[] -* xref::constraints/examples.adoc#constraints-create-a-node-key-constraint-with-index-provider[] -* xref::constraints/examples.adoc#constraints-node-key-and-uniqueness-constraint-on-the-same-schema[] -* xref::constraints/examples.adoc#constraints-create-a-node-key-constraint-with-the-same-name-as-existing-index[] -* xref::constraints/examples.adoc#constraints-create-a-node-that-complies-with-a-node-key-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-node-that-violates-a-node-key-constraint[] -* xref::constraints/examples.adoc#constraints-removing-a-node-key-constrained-property[] -* xref::constraints/examples.adoc#constraints-fail-to-create-a-node-key-constraint-due-to-existing-node[] - - -[[constraints-create-a-node-key-constraint]] -=== Create a node key constraint - -When creating a node key constraint, it is recommended to provide a constraint name. - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT actor_fullname -FOR (actor:Actor) REQUIRE (actor.firstname, actor.surname) IS NODE KEY ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - -[role=label--new-5.16] -[[constraints-create-a-node-key-constraint-by-param]] -=== Create a node key constraint using a parameter - -The constraint name can also be given as a parameter. - -.+CREATE CONSTRAINT+ -====== - -.Parameters -[source, parameters] ----- -{ - "name": "node_key_param" -} ----- - -.Query -[source, cypher] ----- -CREATE CONSTRAINT $name -FOR (actor:Actor) REQUIRE actor.firstname IS KEY ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - - -[[constraints-create-a-node-key-constraint-if-not-exist]] -=== Handling existing constraints when creating a constraint - -Creating an already existing constraint will fail. -To avoid such an error, `IF NOT EXISTS` can be added to the `CREATE` command. -This will ensure that no error is thrown and that no constraint is created if any other constraint with the given name, or another node key constraint on the same schema, already exists. -As of Neo4j 5.17, an informational notification is instead returned showing the existing constraint which blocks the creation. - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT actor_names IF NOT EXISTS -FOR (actor:Actor) REQUIRE (actor.firstname, actor.surname) IS NODE KEY ----- - -Assuming a node key constraint on `(:Actor {firstname, surname})` already exists: - -.Result -[queryresult] ----- -(no changes, no records) ----- - -.Notification -[source] ----- -`CREATE CONSTRAINT actor_names IF NOT EXISTS FOR (e:Actor) REQUIRE (e.firstname, e.surname) IS NODE KEY` has no effect. -`CONSTRAINT actor_fullname FOR (e:Actor) REQUIRE (e.firstname, e.surname) IS NODE KEY` already exists. ----- - -====== - - -[[constraints-create-a-node-key-constraint-with-index-provider]] -=== Specifying an index provider when creating a constraint - -To create a node key constraint with a specific index provider for the backing index, the `OPTIONS` clause is used. - -The index type of the backing index is set with the `indexProvider` option. - -The only valid value for the index provider is: - -* `range-1.0` label:default[] - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT constraint_with_provider -FOR (actor:Actor) REQUIRE (actor.surname) IS NODE KEY -OPTIONS { - indexProvider: 'range-1.0' -} ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - -There is no valid index configuration values for the constraint-backing range indexes. - - -[[constraints-node-key-and-uniqueness-constraint-on-the-same-schema]] -=== Node key and property uniqueness constraints are not allowed on the same schema - - -.+CREATE CONSTRAINT+ -====== - -Create a node key constraint on the properties `firstname` and `age` on nodes with the `Actor` label, when a property uniqueness constraint already exists on the same label and property combination: - -//// -[source, cypher, role=test-setup] ----- -CREATE CONSTRAINT preExisting_actor_name_age FOR (actor:Actor) REQUIRE (actor.firstname, actor.age) IS UNIQUE ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT actor_name_age FOR (actor:Actor) REQUIRE (actor.firstname, actor.age) IS NODE KEY ----- - -In this case, the constraint cannot be created because there already exist a conflicting constraint on that label and property combination. - -.Error message -[source, error] ----- -Constraint already exists: -Constraint( id=10, name='preExisting_actor_name_age', type='UNIQUENESS', schema=(:Actor {firstname, age}), ownedIndex=9 ) ----- - -====== - - -[[constraints-create-a-node-key-constraint-with-the-same-name-as-existing-index]] -=== Creating a constraint on same name as an existing index will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a named node key constraint on the property `citizenship` on nodes with the `Actor` label, when an index already exists with the given name: - -//// -[source, cypher, role=test-setup] ----- -CREATE INDEX citizenship FOR (person:Person) ON (person.citizenship) ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT citizenship -FOR (actor:Actor) REQUIRE actor.citizenship IS NODE KEY ----- - -In this case, the constraint cannot be created because there already exists an index with the given name. - -.Error message -[source, error] ----- -There already exists an index called 'citizenship'. ----- - -====== - - -[[constraints-create-a-node-that-complies-with-a-node-key-constraint]] -=== Creating a node that complies with an existing constraint - - -.+CREATE NODE+ -====== - -Create an `Actor` node with `firstname` and `surname` properties: - -.Query -[source, cypher] ----- -CREATE (actor:Actor {firstname: 'Keanu', surname: 'Reeves'}) ----- - -.Result -[queryresult] ----- -Added 1 label, created 1 node, set 2 properties. ----- - -====== - - -[[constraints-create-a-node-that-violates-a-node-key-constraint]] -=== Creating a node that violates an existing constraint will fail - - -.+CREATE NODE+ -====== - -Create an `Actor` node without a `firstname` property, given a node key constraint on `:Actor(firstname, surname)`: - - -.Query -[source, cypher, role=test-fail] ----- -CREATE (actor:Actor {surname: 'Wood'}) ----- - -In this case, the node is not created because it is missing the `firstname` property which is in conflict with an existing constraint. - -.Error message -[source, error] ----- -Node(0) with label `Actor` must have the properties (`firstname`, `surname`) ----- - -====== - - -[[constraints-removing-a-node-key-constrained-property]] -=== Removing a +NODE KEY+-constrained property will fail - - -.+REMOVE PROPERTY+ -====== - -Remove the `firstname` property from an existing node `Actor`, given a `NODE KEY` constraint on `:Actor(firstname, surname)`: - -.Query -[source, cypher, role=test-fail] ----- -MATCH (actor:Actor {firstname: 'Keanu', surname: 'Reeves'}) REMOVE actor.firstname ----- - -In this case, the property is not removed because it is in conflict with an existing constraint. - -.Error message -[source, error] ----- -Node(0) with label `Actor` must have the properties (`firstname`, `surname`) ----- - -====== - - -[[constraints-fail-to-create-a-node-key-constraint-due-to-existing-node]] -=== Creating a constraint when there exist conflicting node will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a node key constraint on the property `born` on nodes with the `Actor` label, when a node without a `born` property already exists in the graph: - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT actor_born FOR (actor:Actor) REQUIRE (actor.born) IS NODE KEY ----- - -In this case, the node key constraint cannot be created because it is in conflict with the existing graph. -Either use xref:indexes/search-performance-indexes/managing-indexes.adoc[] instead, or remove/correct the offending nodes and then re-apply the constraint. - -.Error message -[source, error] ----- -Unable to create Constraint( type='NODE KEY', schema=(:Actor {born}) ): -Node(0) with label `Actor` must have the property `born` ----- - -====== - -The constraint creation fails on the first offending nodes that are found. -This does not guarantee that there are no other offending nodes in the graph. -Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. - -This is an example `MATCH` query to find all offending nodes for the constraint above: - -.Query -[source, cypher] ----- -MATCH (actor1:Actor), (actor2:Actor) -WHERE actor1.born = actor2.born AND NOT actor1 = actor2 -UNWIND [actor1, actor2] AS actor -RETURN actor, 'non-unique' AS reason - -UNION - -MATCH (actor:Actor) -WHERE actor.born IS NULL -RETURN actor, 'non-existing' AS reason ----- - - -[role=label--enterprise-edition label--new-5.7] -[[constraints-examples-relationship-key]] -== Relationship key constraints - -A relationship key constraint ensures that certain relationships have a set of defined properties whose combined value is unique. -It also ensures that all properties in the set are present. - -* xref::constraints/examples.adoc#constraints-create-a-relationship-key-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-key-constraint-by-param[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-key-constraint-if-not-exist[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-key-constraint-with-index-provider[] -* xref::constraints/examples.adoc#constraints-relationship-key-and-uniqueness-constraint-on-the-same-schema[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-key-constraint-with-the-same-name-as-existing-index[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-that-complies-with-a-relationship-key-constraint[] -* xref::constraints/examples.adoc#constraints-create-a-relationship-that-violates-a-relationship-key-constraint[] -* xref::constraints/examples.adoc#constraints-removing-a-relationship-key-constrained-property[] -* xref::constraints/examples.adoc#constraints-fail-to-create-a-relationship-key-constraint-due-to-existing-relationship[] - - -[[constraints-create-a-relationship-key-constraint]] -=== Create a relationship key constraint - -When creating a relationship key constraint, it is recommended to provide a constraint name. - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT knows_since_how -FOR ()-[knows:KNOWS]-() REQUIRE (knows.since, knows.how) IS RELATIONSHIP KEY ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - -[role=label--new-5.16] -[[constraints-create-a-relationship-key-constraint-by-param]] -=== Create a relationship key constraint using a parameter - -The constraint name can also be given as a parameter. - -.+CREATE CONSTRAINT+ -====== - -.Parameters -[source, parameters] ----- -{ - "name": "rel_key_param" -} ----- - -.Query -[source, cypher] ----- -CREATE CONSTRAINT $name -FOR ()-[knows:KNOWS]-() REQUIRE knows.friend IS KEY ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - - -[[constraints-create-a-relationship-key-constraint-if-not-exist]] -=== Handling existing constraints when creating a constraint - -Creating an already existing constraint will fail. -To avoid such an error, `IF NOT EXISTS` can be added to the `CREATE` command. -This will ensure that no error is thrown and that no constraint is created if any other constraint with the given name, or another relationship key constraint on the same schema, already exists. -As of Neo4j 5.17, an informational notification is instead returned showing the existing constraint which blocks the creation. - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT knows IF NOT EXISTS -FOR ()-[knows:KNOWS]-() REQUIRE (knows.since, knows.how) IS RELATIONSHIP KEY ----- - -Assuming a relationship key constraint on `()-[:KNOWS {since, how}]-()` already exists: - -.Result -[queryresult] ----- -(no changes, no records) ----- - -.Notification -[source] ----- -`CREATE CONSTRAINT knows IF NOT EXISTS FOR ()-[e:KNOWS]-() REQUIRE (e.since, e.how) IS RELATIONSHIP KEY` has no effect. -`CONSTRAINT knows_since_how FOR ()-[e:KNOWS]-() REQUIRE (e.since, e.how) IS RELATIONSHIP KEY` already exists. ----- - -====== - - -[[constraints-create-a-relationship-key-constraint-with-index-provider]] -=== Specifying an index provider when creating a constraint - -To create a relationship key constraint with a specific index provider for the backing index, the `OPTIONS` clause is used. - -The index type of the backing index is set with the `indexProvider` option. - -The only valid value for the index provider is: - -* `range-1.0` label:default[] - - -.+CREATE CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -CREATE CONSTRAINT rel_constraint_with_provider -FOR ()-[knows:KNOWS]-() REQUIRE (knows.since) IS REL KEY -OPTIONS { - indexProvider: 'range-1.0' -} ----- - -.Result -[queryresult] ----- -Added 1 constraint. ----- - -====== - -There is no valid index configuration values for the constraint-backing range indexes. - - -[[constraints-relationship-key-and-uniqueness-constraint-on-the-same-schema]] -=== Relationship key and property uniqueness constraints are not allowed on the same schema - - -.+CREATE CONSTRAINT+ -====== - -Create a relationship key constraint on the property `how` on relationships with the `KNOWS` relationship type, when a property uniqueness constraint already exists on the same relationship type and property combination: - -//// -[source, cypher, role=test-setup] ----- -CREATE CONSTRAINT preExisting_how FOR ()-[knows:KNOWS]-() REQUIRE (knows.how) IS UNIQUE ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT knows_how FOR ()-[knows:KNOWS]-() REQUIRE (knows.how) IS REL KEY ----- - -In this case, the constraint cannot be created because there already exists a conflicting constraint on that relationship type and property combination. - -.Error message -[source, error] ----- -Constraint already exists: -Constraint( id=34, name='preExisting_how', type='RELATIONSHIP UNIQUENESS', schema=()-[:KNOWS {how}]-(), ownedIndex=33 ) ----- - -[NOTE] -==== -The constraint type for relationship property uniqueness constraints will be updated to say `RELATIONSHIP PROPERTY UNIQUENESS` in Neo4j 6.0. -==== - -====== - - -[[constraints-create-a-relationship-key-constraint-with-the-same-name-as-existing-index]] -=== Creating a constraint on same name as an existing index will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a named relationship key constraint on the property `level` on relationships with the `KNOWS` relationship type, when an index already exists with the given name: - -//// -[source, cypher, role=test-setup] ----- -CREATE INDEX knows FOR ()-[know:KNOW]-() ON (know.levels) ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT knows -FOR ()-[knows:KNOWS]-() REQUIRE (knows.level) IS REL KEY ----- - -In this case, the constraint cannot be created because there already exists an index with the given name. - -.Error message -[source, error] ----- -There already exists an index called 'knows'. ----- - -====== - - -[[constraints-create-a-relationship-that-complies-with-a-relationship-key-constraint]] -=== Creating a relationship that complies with an existing constraint - - -.+CREATE RELATIONSHIP+ -====== - -Create a `KNOWS` relationship with both `since` and `how` properties and a relationship key constraint on `:KNOWS(since, how)`: - -.Query -[source, cypher] ----- -CREATE (:Actor {firstname: 'Jensen', surname: 'Ackles'})-[:KNOWS {since: 2008, how: 'coworkers', friend: true}]->(:Actor {firstname: 'Misha', surname: 'Collins'}) ----- - -.Result -[queryresult] ----- -Added 2 labels, created 2 nodes, set 6 properties, created 1 relationship. ----- - -====== - - -[[constraints-create-a-relationship-that-violates-a-relationship-key-constraint]] -=== Creating a relationship that violates an existing constraint will fail - - -.+CREATE RELATIONSHIP+ -====== - -Create a `KNOWS` relationship without a `since` property, given a relationship key constraint on `:KNOWS(since, how)`: - -.Query -[source, cypher, role=test-fail] ----- -MATCH (jensen:Actor {firstname: 'Jensen', surname: 'Ackles'}), (misha:Actor {firstname: 'Misha', surname: 'Collins'}) -CREATE (misha)-[:KNOWS {how: 'coworkers'}]->(jensen) ----- - -In this case, the relationship is not created because it is missing the `since` property which is in conflict with an existing constraint. - -.Error message -[source, error] ----- -Relationship(0) already exists with type `KNOWS` and property `how` = 'coworkers' ----- - -====== - - -[[constraints-removing-a-relationship-key-constrained-property]] -=== Removing a +RELATIONSHIP KEY+-constrained property will fail - - -.+REMOVE PROPERTY+ -====== - -Remove the `since` property from an existing relationship `KNOWS`, given a `RELATIONSHIP KEY` constraint on `:KNOWS(since, how)`: - -.Query -[source, cypher, role=test-fail] ----- -MATCH ()-[knows:KNOWS {since: 2008, how: 'coworkers'}]->() REMOVE knows.since ----- - -In this case, the property is not removed because it is in conflict with an existing constraint. - -.Error message -[source, error] ----- -Relationship(0) with type `KNOWS` must have the properties (`since`, `how`) ----- - -====== - - -[[constraints-fail-to-create-a-relationship-key-constraint-due-to-existing-relationship]] -=== Creating a constraint when there exist conflicting relationships will fail - - -.+CREATE CONSTRAINT+ -====== - -Create a relationship key constraint on the property `level` on relationships with the `KNOWS` relationship type, when two relationships with identical `level` property values already exist in the graph: - -//// -[source, cypher, role=test-setup] ----- -MATCH (jensen:Actor {firstname: 'Jensen', surname: 'Ackles'})-[knows:KNOWS {since: 2008, how: 'coworkers'}]->(:Actor {firstname: 'Misha', surname: 'Collins'}) -SET knows.level = 10 -CREATE (jensen)-[:KNOWS {since: 2005, how: 'costars', friend: false, level: 10}]->(:Actor {firstname: 'Jared', surname: 'Padalecki'}) ----- -//// - -.Query -[source, cypher, role=test-fail] ----- -CREATE CONSTRAINT knows_level FOR ()-[knows:KNOWS]-() REQUIRE (knows.level) IS REL KEY ----- - -In this case, the relationship key constraint cannot be created because it is in conflict with the existing graph. -Either use xref:indexes/search-performance-indexes/managing-indexes.adoc[] instead, or remove or correct the offending relationships and then re-apply the constraint. - -.Error message -[source, error] ----- -Unable to create Constraint( name='knows_level', type='RELATIONSHIP KEY', schema=()-[:KNOWS {level}]-() ): -Both Relationship(0) and Relationship(1) have the type `KNOWS` and property `level` = 10 ----- - -====== - -The constraint creation fails on the first offending relationships that are found. -This does not guarantee that there are no other offending relationships in the graph. -Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. - -This is an example `MATCH` query to find all offending relationships for the constraint above: - -.Query -[source, cypher] ----- -MATCH ()-[knows1:KNOWS]->(), ()-[knows2:KNOWS]->() -WHERE knows1.level = knows2.level AND NOT knows1 = knows2 -UNWIND [knows1, knows2] AS knows -RETURN knows, 'non-unique' AS reason -UNION -MATCH ()-[knows:KNOWS]->() -WHERE knows.level IS NULL -RETURN knows, 'non-existing' AS reason ----- - - -[[constraints-examples-drop-constraint]] -== Drop a constraint by name - -A constraint can be dropped using the name with the `DROP CONSTRAINT constraint_name` command. -It is the same command for all constraint types. -The name of the constraint can be found using the xref::constraints/syntax.adoc#constraints-syntax-list[`SHOW CONSTRAINTS` command], given in the output column `name`. - -* xref::constraints/examples.adoc#constraints-drop-a-constraint[] -* xref::constraints/examples.adoc#constraints-drop-a-constraint-by-param[] -* xref::constraints/examples.adoc#constraints-drop-a-non-existing-constraint[] - - -[[constraints-drop-a-constraint]] -=== Drop a constraint - -A constraint can be dropped using the name with the `DROP CONSTRAINT` command. - - -.+DROP CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -DROP CONSTRAINT book_isbn ----- - -.Result -[queryresult] ----- -Removed 1 constraint. ----- - -====== - - -[role=label--new-5.16] -[[constraints-drop-a-constraint-by-param]] -=== Drop a constraint using a parameter - -The constraint name can also be given as a parameter. - -.+DROP CONSTRAINT+ -====== - -.Parameters -[source, parameters] ----- -{ - "name": "node_uniqueness_param" -} ----- - -.Query -[source, cypher] ----- -DROP CONSTRAINT $name ----- - -.Result -[queryresult] ----- -Removed 1 constraint. ----- - -====== - - -[[constraints-drop-a-non-existing-constraint]] -=== Drop a non-existing constraint - -If it is uncertain if any constraint with a given name exists and you want to drop it if it does but not get an error should it not, use `IF EXISTS`. - -.+DROP CONSTRAINT+ -====== - -.Query -[source, cypher] ----- -DROP CONSTRAINT missing_constraint_name IF EXISTS ----- - -.Result -[queryresult] ----- -(no changes, no records) ----- - -.Notification -[source] ----- -`DROP CONSTRAINT missing_constraint_name IF EXISTS` has no effect. `missing_constraint_name` does not exist. ----- - -====== - - -[[constraints-examples-list-constraint]] -== Listing constraints - -* xref::constraints/examples.adoc#constraints-listing-all-constraints[] -* xref::constraints/examples.adoc#constraints-listing-constraints-with-filtering[] - - -[[constraints-listing-all-constraints]] -=== Listing all constraints - -To list all constraints with the default output columns, the `SHOW CONSTRAINTS` command can be used. -If all columns are required, use `SHOW CONSTRAINTS YIELD *`. - -[NOTE] -==== -One of the output columns from `SHOW CONSTRAINTS` is the name of the constraint. -This can be used to drop the constraint with the xref::constraints/syntax.adoc#constraints-syntax-drop[`DROP CONSTRAINT` command]. -==== - - -.+SHOW CONSTRAINTS+ -====== - -.Query -[source, cypher, test-exclude-cols=id] ----- -SHOW CONSTRAINTS ----- - -[queryresult] ----- -+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| id | name | type | entityType | labelsOrTypes | properties | ownedIndex | propertyType | -+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 36 | "actor_fullname" | "NODE_KEY" | "NODE" | ["Actor"] | ["firstname", "surname"] | "actor_fullname" | null | -| 21 | "author_name" | "NODE_PROPERTY_EXISTENCE" | "NODE" | ["Author"] | ["name"] | null | null | -| 24 | "author_pseudonym" | "UNIQUENESS" | "NODE" | ["Author"] | ["pseudonym"] | "author_pseudonym" | null | -| 8 | "book_isbn2" | "UNIQUENESS" | "NODE" | ["Book"] | ["isbn2"] | "book_isbn2" | null | -| 10 | "constraint_with_options" | "UNIQUENESS" | "NODE" | ["Book"] | ["prop1", "prop2"] | "constraint_with_options" | null | -| 40 | "constraint_with_provider" | "NODE_KEY" | "NODE" | ["Actor"] | ["surname"] | "constraint_with_provider" | null | -| 45 | "knows_since_how" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["KNOWS"] | ["since", "how"] | "knows_since_how" | null | -| 30 | "movie_tagline" | "NODE_PROPERTY_TYPE" | "NODE" | ["Movie"] | ["tagline"] | null | "STRING | LIST" | -| 28 | "movie_title" | "NODE_PROPERTY_TYPE" | "NODE" | ["Movie"] | ["title"] | null | "STRING" | -| 22 | "node_exist_param" | "NODE_PROPERTY_EXISTENCE" | "NODE" | ["Author"] | ["surname"] | null | null | -| 38 | "node_key_param" | "NODE_KEY" | "NODE" | ["Actor"] | ["firstname"] | "node_key_param" | null | -| 29 | "node_prop_type_param" | "NODE_PROPERTY_TYPE" | "NODE" | ["Movie"] | ["prop1"] | null | "INTEGER" | -| 32 | "part_of" | "RELATIONSHIP_PROPERTY_TYPE" | "RELATIONSHIP" | ["PART_OF"] | ["order"] | null | "INTEGER" | -| 34 | "part_of_tags" | "RELATIONSHIP_PROPERTY_TYPE" | "RELATIONSHIP" | ["PART_OF"] | ["tags"] | null | "STRING | LIST" | -| 42 | "preExisting_actor_name_age" | "UNIQUENESS" | "NODE" | ["Actor"] | ["firstname", "age"] | "preExisting_actor_name_age" | null | -| 12 | "preExisting_book_published" | "UNIQUENESS" | "NODE" | ["Book"] | ["published"] | "preExisting_book_published" | null | -| 51 | "preExisting_how" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["KNOWS"] | ["how"] | "preExisting_how" | null | -| 19 | "rel_constraint_with_options" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["SEQUEL_OF"] | ["order", "seriesTitle", "number"] | "rel_constraint_with_options" | null | -| 49 | "rel_constraint_with_provider" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["KNOWS"] | ["since"] | "rel_constraint_with_provider" | null | -| 26 | "rel_exist_param" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["published"] | null | null | -| 47 | "rel_key_param" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["KNOWS"] | ["friend"] | "rel_key_param" | null | -| 33 | "rel_prop_type_param" | "RELATIONSHIP_PROPERTY_TYPE" | "RELATIONSHIP" | ["PART_OF"] | ["prop1"] | null | "FLOAT" | -| 17 | "rel_uniqueness_param" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["SEQUEL_OF"] | ["prop1"] | "rel_uniqueness_param" | null | -| 15 | "sequels" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["SEQUEL_OF"] | ["order", "seriesTitle"] | "sequels" | null | -| 31 | "seriesOrder" | "NODE_PROPERTY_TYPE" | "NODE" | ["Movie"] | ["seriesOrder"] | null | "INTEGER" | -| 27 | "wrote_locations" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["location"] | null | null | -| 25 | "wrote_year" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["year"] | null | null | -+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -27 rows ----- - -[NOTE] -==== -The `type` column returns `UNIQUENESS` for the node property uniqueness constraint and `RELATIONSHIP_UNIQUENESS` for the relationship property uniqueness constraint. -This will be updated in Neo4j 6.0. -Node property uniqueness constraints will be updated to `NODE_PROPERTY_UNIQUENESS` and relationship property uniqueness constraints to `RELATIONSHIP_PROPERTY_UNIQUENESS`. -==== - -====== - - -[[constraints-listing-constraints-with-filtering]] -=== Listing constraints with filtering - -One way of filtering the output from `SHOW CONSTRAINTS` by constraint type is the use of constraint type keywords, -listed in the xref::constraints/syntax.adoc#constraints-syntax-list-type-filter[syntax for listing constraints type filter table]. -For example, to show only property uniqueness constraints, use `SHOW UNIQUENESS CONSTRAINTS`. -Another more flexible way of filtering the output is to use the `WHERE` clause. -An example is to only show constraints on relationships. - - -.+SHOW CONSTRAINTS+ -====== - -.Query -[source, cypher, test-exclude-cols=id] ----- -SHOW EXISTENCE CONSTRAINTS -WHERE entityType = 'RELATIONSHIP' ----- - -This will only return the default output columns. -To get all columns, use `+SHOW INDEXES YIELD * WHERE ...+`. - -[queryresult] ----- -+-----------------------------------------------------------------------------------------------------------------------------------------+ -| id | name | type | entityType | labelsOrTypes | properties | ownedIndex | propertyType | -+-----------------------------------------------------------------------------------------------------------------------------------------+ -| 26 | "rel_exist_param" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["published"] | null | null | -| 27 | "wrote_locations" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["location"] | null | null | -| 25 | "wrote_year" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["year"] | null | null | -+-----------------------------------------------------------------------------------------------------------------------------------------+ -3 rows ----- - -====== - diff --git a/modules/ROOT/pages/constraints/index.adoc b/modules/ROOT/pages/constraints/index.adoc index 2d5677e04..f906e317b 100644 --- a/modules/ROOT/pages/constraints/index.adoc +++ b/modules/ROOT/pages/constraints/index.adoc @@ -1,124 +1,16 @@ -:description: This section explains how to manage constraints used for ensuring data integrity. +:description: Overview of Neo4j's constraints used for ensuring data integrity. include::https://raw.githubusercontent.com/neo4j-graphacademy/courses/main/asciidoc/courses/cypher-indexes-constraints/ad.adoc[] - -[[constraints]] = Constraints -This page contains an overview of the available constraints in Cypher, and information about how constraints can impact indexes. - -Adding constraints is an atomic operation that can take a while -- all existing data has to be scanned before a Neo4j DBMS can use a constraint. - -[[unique-node-property]] -== Unique node property constraints -Unique node property constraints, or node property uniqueness constraints, ensure that property values are unique for all nodes with a specific label. -For property uniqueness constraints on multiple properties, the combination of the property values is unique. -Node property uniqueness constraints do not require all nodes to have a unique value for the properties listed (nodes without all properties on which the constraint exists are not subject to this rule). - -For more information, see xref:constraints/examples.adoc#constraints-examples-node-uniqueness[examples of node property uniqueness constraints]. - -[role=label--new-5.7] -[[unique-relationship-property]] -== Unique relationship property constraints - -Unique relationship property constraints, or relationship property uniqueness constraints, ensure that property values are unique for all relationships with a specific type. -For property uniqueness constraints on multiple properties, the combination of the property values is unique. -Relationship property uniqueness constraints do not require all relationships to have a unique value for the properties listed (relationships without all properties on which the constraint exists are not subject to this rule). - -For more information, see xref:constraints/examples.adoc#constraints-examples-relationship-uniqueness[examples of relationship property uniqueness constraints]. - -[[node-property-existence]] -[role=label--enterprise-edition] -== Node property existence constraints - -Node property existence constraints ensure that a property exists for all nodes with a specific label. -Queries that try to create new nodes of the specified label, but without this property, will fail. -The same is true for queries that try to remove the mandatory property. - -For more information, see xref:constraints/examples.adoc#constraints-examples-node-property-existence[examples of node property existence constraints]. - -[[relationship-property-existence]] -[role=label--enterprise-edition] -== Relationship property existence constraints - -Relationship property existence constraints ensure that a property exists for all relationships with a specific type. -All queries that try to create relationships of the specified type, but without this property, will fail. -The same is true for queries that try to remove the mandatory property. - -For more information, see xref:constraints/examples.adoc#constraints-examples-relationship-property-existence[examples of relationship property existence constraints]. - -[[node-property-type]] -[role=label--enterprise-edition label--new-5.9] -== Node property type constraints - -Node property type constraints ensure that a property have the required property type for all nodes with a specific label. -Queries that try to add or modify this property to nodes of the specified label, but with a different property type, will fail. -Node property type constraints do not require all nodes to have the property (nodes without the property on which the constraint exists are not subject to this rule). - -For more information, see xref:constraints/examples.adoc#constraints-examples-node-property-type[examples of node property type constraints]. - -[[relationship-property-type]] -[role=label--enterprise-edition label--new-5.9] -== Relationship property type constraints - -Relationship property type constraints ensure that a property have the required property type for all relationships with a specific type. -Queries that try to add or modify this property to relationships of the specified type, but with a different property type, will fail. -Relationship property type constraints do not require all relationships to have the property (relationships without the property on which the constraint exists are not subject to this rule). - -For more information, see xref:constraints/examples.adoc#constraints-examples-relationship-property-type[examples of relationship property type constraints]. - -[[node-key]] -[role=label--enterprise-edition] -== Node key constraints - -Node key constraints ensure that, for a given label and set of properties: - -. All the properties exist on all the nodes with that label. -. The combination of the property values is unique. - -+ -Queries attempting to do any of the following will fail: - -* Create new nodes without all the properties or where the combination of property values is not unique. -* Remove one of the mandatory properties. -* Update the properties so that the combination of property values is no longer unique. - -For more information, see xref:constraints/examples.adoc#constraints-examples-node-key[examples of node key constraints]. - -[[relationship-key]] -[role=label--enterprise-edition label--new-5.7] -== Relationship key constraints - -Relationship key constraints ensure that, for a given type and set of properties: - -[lowerroman] -. All the properties exist on all the relationships with that type. -. The combination of the property values is unique. - -+ -Queries attempting to do any of the following will fail: - -* Create new relationships without all the properties or where the combination of property values is not unique. -* Remove one of the mandatory properties. -* Update the properties so that the combination of property values is no longer unique. - -For more information, see xref:constraints/examples.adoc#constraints-examples-relationship-key[examples of relationship key constraints]. - -[[multiple-constrains]] -== Multiple constraints on the same property combinations - - -Some constraint types are allowed on the same label/relationship type and property combination. -For example, it is possible to have a uniqueness and an existence constraint on the same label/relationship type and property combination, though this would be the equivalent of having a node or relationship key constraint. -A more useful example would be to combine a property type and an existence constraint to ensure that the property exists and has the given type. +Neo4j offers several constraints to ensure the quality and integrity of data in a graph. +The following constraints are available in Neo4j: -[[index-implications]] -== Implications on indexes +* *Property uniqueness constraints* ensure that the combined property values are unique for all nodes with a specific label or all relationships with a specific type. +* *Property existence constraints* ensure that a property exists either for all nodes with a specific label or for all relationships with a specific type. label:enterprise-edition[] +* *Property type constraints* ensure that a property has the required property type for all nodes with a specific label or for all relationships with a specific type. label:enterprise-edition[] +* *Key constraints* ensure that all properties exist and that the combined property values are unique for all nodes with a specific label or all relationships with a specific type.label:enterprise-edition[] -Creating a constraint has the following implications on indexes: +To learn more about creating, listing, and dropping these constraints, as well as information about index-backed constraints, constraint creation failures and data violation scenarios, and more, see xref:constraints/managing-constraints.adoc[]. -* Adding a node key, relationship key, or property uniqueness constraint on a single property also adds an index on that property, and therefore, an index of the same index type, label/relationship type, and property combination cannot be added separately. -* Adding a node key, relationship key, or property uniqueness constraint for a set of properties also adds an index on those properties, and therefore, an index of the same index type, label/relationship type, and properties combination cannot be added separately. -* Cypher will use these indexes for lookups just like other indexes. - Refer to xref:indexes/search-performance-indexes/managing-indexes.adoc[] for more details on indexes. -* If a node key, relationship key, or property uniqueness constraint is dropped and the backing index is still required, the index need to be created explicitly. +For reference material about the Cypher commands used to manage constraints, see xref:constraints/syntax.adoc[]. diff --git a/modules/ROOT/pages/constraints/managing-constraints.adoc b/modules/ROOT/pages/constraints/managing-constraints.adoc new file mode 100644 index 000000000..bcd24e97b --- /dev/null +++ b/modules/ROOT/pages/constraints/managing-constraints.adoc @@ -0,0 +1,1826 @@ +:description: Information about creating, listing, and dropping Neo4j's constraints. +include::https://raw.githubusercontent.com/neo4j-graphacademy/courses/main/asciidoc/courses/cypher-indexes-constraints/ad.adoc[] += Create, show, and drop constraints + +This page describes how to create, list, and drop constraints. +The following constraint types are available in Neo4j: + +* xref:constraints/managing-constraints.adoc#create-property-uniqueness-constraints[Property uniqueness constraints] +* xref:constraints/managing-constraints.adoc#create-property-existence-constraints[Property existence constraints] label:enterprise-edition[] +* xref:constraints/managing-constraints.adoc#create-property-type-constraints[Property type constraints] label:enterprise-edition[] +* xref:constraints/managing-constraints.adoc#create-key-constraints[Key constraints] label:enterprise-edition[] + + +[[create-constraint]] +== CREATE CONSTRAINT + +Constraints are created with the `CREATE CONSTRAINT` command. +When creating a constraint, it is recommended to provide a constraint name. +This name must be unique among both indexes and constraints. +If a name is not explicitly given, a unique name will be auto-generated. + + +[NOTE] +Creating a constraint requires the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/database-administration/#access-control-database-administration-constraints[`CREATE CONSTRAINT` privilege]. + +[NOTE] +Adding constraints is an atomic operation that can take a while -- all existing data has to be scanned before a Neo4j DBMS can use a constraint. + +[[create-property-uniqueness-constraints]] +=== Create property uniqueness constraints + +Property uniqueness constraints ensure that the property values are unique for all nodes with a specific label or all relationships with a specific type. +For composite property uniqueness constraints on multiple properties, it is the combination of property values that must be unique. +Queries that try to add duplicated property values will fail. + +Property uniqueness constraints do not require all nodes or relationships to have values for the properties listed in the constraint. +Only nodes or relationships that contain all properties specified in the constraint are subject to the uniqueness rule. +Nodes or relationships missing one or more of the specified properties are not subject to this rule. + +* xref:constraints/managing-constraints.adoc#create-single-property-uniqueness-constraint[] +* xref:constraints/managing-constraints.adoc#create-composite-property-uniqueness-constraint[] +* xref:constraints/managing-constraints.adoc#create-property-uniqueness-constraint-compliant-data[] + +[[create-single-property-uniqueness-constraint]] +==== Create a single property uniqueness constraint + +Single property uniqueness constraints are created with the following commands: + +* Node property uniqueness constraints: `CREATE CONSTRAINT constraint_name FOR (n:Label) REQUIRE n.property IS UNIQUE`. +* Relationship property uniqueness constraints: `CREATE CONSTRAINT constraint_name +FOR ()-[r:REL_TYPE]-() REQUIRE r.property IS UNIQUE`. label:new[Introduced in 5.7] + +For the full command syntax to create a property uniqueness constraint, see xref:constraints/syntax.adoc#create-property-uniqueness-constraints[Syntax -> Create property uniqueness constraints]. + +.Create a node property uniqueness constraint on a single property +====== + +.Create a constraint requiring `Book` nodes to have unique `isbn` properties +[source, cypher] +---- +CREATE CONSTRAINT book_isbn +FOR (book:Book) REQUIRE book.isbn IS UNIQUE +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +[NOTE] +The detailed statistics view currently says `Unique constraints added: 1`. +It will be updated to say `Node property uniqueness constraints added: 1` in a future version of Neo4j. + +====== + + +.Create a relationship property uniqueness constraint on a single property label:new[Introduced in 5.7] +====== + +.Create a constraint requiring `SEQUEL_OF` relationships to have unique `order` properties +[source, cypher] +---- +CREATE CONSTRAINT sequels +FOR ()-[sequel:SEQUEL_OF]-() REQUIRE sequel.order IS UNIQUE +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +[NOTE] +The detailed statistics view currently says `Relationship uniqueness constraints added: 1`. +It will be updated to say `Relationship property uniqueness constraints added: 1` in a future version of Neo4j. + +====== + +[[create-composite-property-uniqueness-constraint]] +==== Create a composite property uniqueness constraint + +Constraints created for multiple properties are called composite constraints. +Note that the constrained properties must be parenthesized when creating composite property uniqueness constraints. + +* Node property uniqueness constraints: `CREATE CONSTRAINT constraint_name FOR (n:Label) REQUIRE (n.propertyName_1, ..., n.propertyName_n) IS UNIQUE`. +* Relationship property uniqueness constraints: `CREATE CONSTRAINT constraint_name FOR ()-[r:REL_TYPE]-() REQUIRE (r.propertyName_1, ..., r.propertyName_n) IS UNIQUE`. label:new[Introduced in 5.7] + +For the full command syntax to create a property uniqueness constraint, see xref:constraints/syntax.adoc#create-property-uniqueness-constraints[Syntax -> Create property uniqueness constraints]. + +.Create a composite node property uniqueness constraint on several properties +====== + +.Create a constraint requiring `Book` nodes to have unique combinations of `title` and `publicationYear` properties +[source, cypher] +---- +CREATE CONSTRAINT book_title_year +FOR (book:Book) REQUIRE (book.title, book.publicationYear) IS UNIQUE +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + + +.Create a composite relationship property uniqueness constraint on several properties label:new[Introduced in 5.7] +====== + +.Create a constraint requiring `PREQUEL_OF` relationships to have unique combinations of `order` and `author` properties +[source, cypher] +---- +CREATE CONSTRAINT prequels +FOR ()-[prequel:PREQUEL_OF]-() REQUIRE (prequel.order, prequel.author) IS UNIQUE +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +[[create-property-uniqueness-constraint-compliant-data]] +==== Create data that complies with existing property uniqueness constraints + +.Create a node that complies with existing property uniqueness constraints +====== + +.Create a `Book` node with a unique `isbn` property +[source, cypher] +---- +CREATE (book:Book {isbn: '1449356265', title: 'Graph Databases'}) +---- + +.Result +[source, queryresult] +---- +Added 1 label, created 1 node, set 2 properties +---- + +====== + + +.Create a relationship that complies with existing property uniqueness constraints +====== + +.Create a `SEQUEL_OF` relationship with a unique `order` property +[source, cypher] +---- +CREATE (:Book {title: 'Spirit Walker'})-[:SEQUEL_OF {order: 1, seriesTitle: 'Chronicles of Ancient Darkness'}]->(:Book {title: 'Wolf Brother'}) +---- + +.Result +[source, queryresult] +---- +Added 2 labels, created 2 nodes, set 4 properties, created 1 relationship. +---- + +====== + +[role=label--enterprise-edition] +[[create-property-existence-constraints]] +=== Create property existence constraints + +Property existence constraints ensure that a property exists either for all nodes with a specific label or for all relationships with a specific type. +Queries that try to create new nodes of the specified label, or relationships of the specified type, without the constrained property will fail. +The same is true for queries that try to remove the mandatory property. + +* xref:constraints/managing-constraints.adoc#create-single-property-existence-constraint[] +* xref:constraints/managing-constraints.adoc#create-property-existence-constraint-compliant-data[] + + +[[create-single-property-existence-constraint]] +==== Create a single property existence constraint + +Property existence constraints on single properties are created with the following commands: + +* Node property existence constraint: `CREATE CONSTRAINT constraint_name FOR (n:Label) REQUIRE n.property IS NOT NULL`. +* Relationship property existence constraint: `CREATE CONSTRAINT constraint_name FOR ()-[r:REL_TYPE]-() REQUIRE r.property IS NOT NULL`. + +For the full command syntax to create an existence constraint, see xref:constraints/syntax.adoc#create-property-existence-constraints[Syntax -> Create property existence constraints]. + +[NOTE] +It is not possible to create composite existence constraints on several properties. + +.Create a node property existence constraint +====== + +.Create a constraint requiring `Author` nodes to have a `name` property +[source, cypher] +---- +CREATE CONSTRAINT author_name +FOR (author:Author) REQUIRE author.name IS NOT NULL +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + + +.Create a relationship property existence constraint +====== + +.Create a constraint requiring `WROTE` relationships to have a `year` property +[source, cypher] +---- +CREATE CONSTRAINT wrote_year +FOR ()-[wrote:WROTE]-() REQUIRE wrote.year IS NOT NULL +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +[[create-property-existence-constraint-compliant-data]] +==== Create data that complies with existing property existence constraints + +.Create a node that complies with existing node property existence constraints +====== + +.Create an `Author` node with a `name` property: +[source, cypher] +---- +CREATE (author:Author {name:'Virginia Woolf', surname: 'Woolf'}) +---- + +.Result +[source, queryresult] +---- +Added 1 label, created 1 node, set 2 properties +---- + +====== + + +.Create a relationship that complies with existing relationship property existence constraints +====== + +.Create a `WROTE` relationship with a `year` property +[source, cypher] +---- +CREATE (author:Author {name: 'Emily Brontë', surname: 'Brontë'})-[wrote:WROTE {year: 1847, location: 'Haworth, United Kingdom', published: true}]->(book:Book {title:'Wuthering Heights', isbn: 9789186579296}) +---- + +.Result +[source, queryresult] +---- +Added 2 labels, created 2 nodes, set 7 properties, created 1 relationship +---- + +====== + + +[role=label--enterprise-edition label--new-5.9] +[[create-property-type-constraints]] +=== Create property type constraints + +Property type constraints ensure that a property has the required data type for all nodes with a specific label or for all relationships with a specific type. +Queries that attempt to add this property with the wrong data type or modify this property in a way that changes its data type for nodes of the specified label or relationships of the specified type will fail. + +Property type constraints do not require all nodes or relationships to have the property. +Nodes or relationships without the constrained property are not subject to this rule. + +* xref:constraints/managing-constraints.adoc#create-single-property-type-constraint[] +* xref:constraints/managing-constraints.adoc#create-property-type-constraint-union-type[] +* xref:constraints/managing-constraints.adoc#type-constraints-allowed-properties[] +* xref:constraints/managing-constraints.adoc#fail-to-create-property-type-constraint-invalid-type[] +* xref:constraints/managing-constraints.adoc#create-property-type-constraint-compliant-data[] + +[[create-single-property-type-constraint]] +==== Create a single property type constraint + +Property type constraints are created with the following commands: + +* Node property type constraints: `CREATE CONSTRAINT constraint_name FOR (n:Label) REQUIRE n.property IS :: `. +* Relationship property type constraints: `CREATE CONSTRAINT constraint_name FOR ()-[r:REL_TYPE]-() REQUIRE r.property IS :: `. + +`` refers to a specific Cypher data type, such as `STRING` or `INTEGER`. +For the types that properties can be constrained by, see xref:constraints/managing-constraints.adoc#type-constraints-allowed-properties[], and for information about different data types in Cypher, see xref:values-and-types/index.adoc[]. +For the full command syntax to create a property type constraint, see xref:constraints/syntax.adoc#create-property-type-constraints[Syntax -> Create property type constraints]. + +[NOTE] +It is not possible to create composite property type constraints on several properties. + +.Create a node property type constraint +====== + +.Create a constraint requiring `title` properties on `Movie` nodes to be of type `STRING` +[source, cypher] +---- +CREATE CONSTRAINT movie_title +FOR (movie:Movie) REQUIRE movie.title IS :: STRING +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- +====== + +.Create a relationship property type constraint +====== + +.Create a constraint requiring `order` properties on `PART_OF` relationships to be of type `INTEGER` +[source, cypher] +---- +CREATE CONSTRAINT part_of +FOR ()-[part:PART_OF]-() REQUIRE part.order IS :: INTEGER +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +[role=label--new-5.11] +[[create-property-type-constraint-union-type]] +==== Create property type constraints with a union type + +A closed dynamic union allows a node or relationship property to maintain some type flexibility whilst preventing unexpected values from being stored. + +.Create a node property type constraint with a union type +====== + +.Create a constraint requiring `tagline` properties on `Movie` nodes to be either of type `STRING` or `LIST` +[source, cypher] +---- +CREATE CONSTRAINT movie_tagline +FOR (movie:Movie) REQUIRE movie.tagline IS :: STRING | LIST +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +.Create a relationship property type constraint with a union type +====== + +.Create a constraint requiring `tags` properties on `PART_OF` relationships to either of type `STRING` or `LIST` +[source, cypher] +---- +CREATE CONSTRAINT part_of_tags +FOR ()-[part:PART_OF]-() REQUIRE part.tags IS :: STRING | LIST +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +[[type-constraints-allowed-properties]] +==== Allowed types + +The allowed property types for property type constraints are: + +* `BOOLEAN` +* `STRING` +* `INTEGER` +* `FLOAT` +* `DATE` +* `LOCAL TIME` +* `ZONED TIME` +* `LOCAL DATETIME` +* `ZONED DATETIME` +* `DURATION` +* `POINT` +* `LIST` label:new[Introduced in 5.10] +* `LIST` label:new[Introduced in 5.10] +* `LIST` label:new[Introduced in 5.10] +* `LIST` label:new[Introduced in 5.10] +* `LIST` label:new[Introduced in 5.10] +* `LIST` label:new[Introduced in 5.10] +* `LIST` label:new[Introduced in 5.10] +* `LIST` label:new[Introduced in 5.10] +* `LIST` label:new[Introduced in 5.10] +* `LIST` label:new[Introduced in 5.10] +* `LIST` label:new[Introduced in 5.10] +* Any closed dynamic union of the above types, e.g. `INTEGER | FLOAT | STRING`. label:new[Introduced in 5.11] + +For a complete reference describing all types available in Cypher, see the section on xref::values-and-types/property-structural-constructed.adoc#types-synonyms[types and their synonyms]. + +[[fail-to-create-property-type-constraint-invalid-type]] +==== Creating property type constraints on invalid types will fail + +.Create a node property type constraint with an invalid type +====== + +.Create a constraint requiring `imdbScore` properties on `Movie` nodes to be of type `MAP` +[source, cypher, role=test-fail] +---- +CREATE CONSTRAINT score FOR (movie:Movie) REQUIRE movie.imdbScore IS :: MAP +---- + +.Error message +[source, error] +---- +Failed to create node property type constraint: Invalid property type `MAP`. +---- + +====== + +[[create-property-type-constraint-compliant-data]] +==== Create data that complies with existing property type constraints + +.Create a node that complies with existing node property type constraint +====== + +.Create an `Movie` node with a `STRING` `title` property +[source, cypher] +---- +CREATE (movie:Movie {title:'Iron Man'}) +---- + +.Result +[source, queryresult] +---- +Added 1 label, created 1 node, set 1 properties +---- + +====== + +.Create a relationship that complies with existing relationship property type constraint +====== + +.Create a `PART_OF` relationship with an `INTEGER` `order` property +[source, cypher] +---- +MATCH (movie:Movie {title:'Iron Man'}) +CREATE (movie)-[part:PART_OF {order: 3}]->(franchise:Franchise {name:'MCU'}) +---- + +.Result +[queryresult] +---- +Added 1 label, added 1 node, created 1 relationship, set 2 properties +---- + +====== + + + +[role=label--enterprise-edition] +[[create-key-constraints]] +=== Create key constraints + +Key constraints ensure that the property exist and the property value is unique for all nodes with a specific label or all relationships with a specific type. +For composite key constraints on multiple properties, all properties must exists and the combination of property values must be unique. + +Queries that try to create new nodes of the specified label, or relationships of the specified type, without the constrained property will fail. +The same is true for queries that try to remove the mandatory property or add duplicated property values. + +* xref:constraints/managing-constraints.adoc#create-single-property-key-constraint[] +* xref:constraints/managing-constraints.adoc#create-composite-key-constraint[] +* xref:constraints/managing-constraints.adoc#create-key-constraint-compliant-data[] + +[[create-single-property-key-constraint]] +==== Create a single property key constraint + +Single property key constraints are created with the following commands: + +* Node key constraints: `CREATE CONSTRAINT constraint_name FOR (n:Label) REQUIRE n.property IS NODE KEY`. +* Relationship key constraints: `CREATE CONSTRAINT constraint_name FOR ()-[r:REL_TYPE]-() REQUIRE r.property IS RELATIONSHIP KEY`. label:new[Introduced in 5.7] + +For the full command syntax to create a key constraint, see xref:constraints/syntax.adoc#create-key-constraints[Syntax -> Create key constraints]. + +.Create a node key constraint on a single property +====== + +.Create a constraint requiring `Director` nodes to have a unique `imdbId` property as a node key. +[source, cypher] +---- +CREATE CONSTRAINT director_imdbId +FOR (director:Director) REQUIRE (director.imdbId) IS NODE KEY +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + + +.Create a relationship key constraint on a single property label:new[Introduced in 5.7] +====== + +.Create a constraint requiring `OWNS` relationships to have a unique `ownershipId` property as a relationship key +[source, cypher] +---- +CREATE CONSTRAINT ownershipId +FOR ()-[owns:OWNS]-() REQUIRE owns.ownershipId IS RELATIONSHIP KEY +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +[[create-composite-key-constraint]] +==== Create a composite key constraint + +Constraints created for multiple properties are called composite constraints. +Note that the constrained properties must be parenthesized when creating composite key constraints. + +Composite key constraints are created with the following commands: + +* Node key constraints: `CREATE CONSTRAINT constraint_name FOR (n:Label) REQUIRE (n.propertyName_1, ..., n.propertyName_n) IS NODE KEY`. +* Relationship key constraints: `CREATE CONSTRAINT constraint_name FOR ()-[r:REL_TYPE]-() REQUIRE (r.propertyName_1, ..., r.propertyName_n) IS RELATIONSHIP KEY`. label:new[Introduced in 5.7] + +For the full command syntax to create a key constraint, see xref:constraints/syntax.adoc#create-key-constraints[Syntax -> Create key constraints]. + +.Create a composite node key constraint on multiple properties +====== + +.Create a constraint requiring `Actor` nodes to have a unique combination of `firstname` and `surname` properties as a node key +[source, cypher] +---- +CREATE CONSTRAINT actor_fullname +FOR (actor:Actor) REQUIRE (actor.firstname, actor.surname) IS NODE KEY +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +.Create a composite relationship key constraint label on multiple properties label:new[Introduced in 5.7] +====== + +.Create a constraint requiring `KNOWS` relationships to have a unique combination of `since` and `how` properties as a relationship key +[source, cypher] +---- +CREATE CONSTRAINT knows_since_how +FOR ()-[knows:KNOWS]-() REQUIRE (knows.since, knows.how) IS RELATIONSHIP KEY +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +[[create-key-constraint-compliant-data]] +==== Create data that complies with existing key constraints + +.Create a node that complies with existing node key constraints +====== + +.Create an `Actor` node with unique `firstname` and `surname` properties +[source, cypher] +---- +CREATE (actor:Actor {firstname: 'Keanu', surname: 'Reeves'}) +---- + +.Result +[source, queryresult] +---- +Added 1 label, created 1 node, set 2 properties. +---- + +====== + + +.Create a relationship that complies with existing relationship key constraints +====== + +.Create a `KNOWS` relationship with unique `since` and `how` properties +[source, cypher] +---- +CREATE (:Actor {firstname: 'Jensen', surname: 'Ackles'})-[:KNOWS {since: 2008, how: 'coworkers', friend: true}]->(:Actor {firstname: 'Misha', surname: 'Collins'}) +---- + +.Result +[source, queryresult] +---- +Added 2 labels, created 2 nodes, set 7 properties, created 1 relationship. +---- + +====== + + +[role=label--new-5.16] +[[create-constraint-with-parameter]] +=== Create a constraint with a parameter + +All constraint types can be created with a parameterized name. + +.Create a node property uniqueness constraint using a parameter +====== + +.Parameters +[source, parameters] +---- +{ + "name": "node_uniqueness_param" +} +---- + +.Create a node property uniqueness constraint with a parameterized name +[source, cypher] +---- +CREATE CONSTRAINT $name +FOR (book:Book) REQUIRE book.prop1 IS UNIQUE +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +.Create a relationship property existence constraint using a parameter +====== + +.Parameters +[source, parameters] +---- +{ + "name": "rel_exist_param" +} +---- + +.Create a relationship property existence constraint with a parameterized name +[source, cypher] +---- +CREATE CONSTRAINT $name +FOR ()-[wrote:WROTE]-() REQUIRE wrote.published IS NOT NULL +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +[[handling-multiple-constraints]] +=== Handling multiple constraints + +Creating an already existing constraint will fail. +This includes the following scenarios: + +* Creating a constraint identical to an already existing constraint. +* Creating a constraint with a different name but on the same constraint type and same label/relationship type and property combination as an already existing constraint. +For property type constraints the property type also needs to be the same. +* Creating a constraint with the same name as an already existing constraint, regardless of what that constraint is. + +Additionally, some constraints cannot coexist and attempting to create them together will therefore fail as well. +This includes: + +* Property type constraints on the same label/relationship type and property but with different property types. +* Property uniqueness and key constraints on the same label/relationship type and property combination. + +However, some constraint types are allowed on the same label/relationship type and property combination. +For example, it is possible to have a property uniqueness and a property existence constraint on the same label/relationship type and property combination, though this would be the equivalent of having a node or relationship key constraint. +A more useful example would be to combine a property type and a property existence constraint to ensure that the property exists and has the given type. + +* xref:constraints/managing-constraints.adoc#create-a-constraint-if-not-exist[] +* xref:constraints/managing-constraints.adoc#create-an-already-existing-constraint[] + +[[create-a-constraint-if-not-exist]] +==== Handling existing constraints when creating a constraint + +To avoid failing on existing constraints, `IF NOT EXISTS` can be added to the `CREATE` command. +This will ensure that no error is thrown and that no constraint is created if any other constraint with the given name, or another constraint on the same constraint type and schema, or both, already exists. +For property type constraints the property type also needs to be the same. +As of Neo4j 5.17, an informational notification is instead returned showing the existing constraint which blocks the creation. + +.Create a constraint identical to an existing constraint +====== + +.Create a constraint requiring all `SEQUEL_OF` relationships to have unique `order` properties +[source, cypher] +---- +CREATE CONSTRAINT sequels IF NOT EXISTS +FOR ()-[sequel:SEQUEL_OF]-() REQUIRE sequel.order IS UNIQUE +---- + +Because the same constraint already exists, nothing will happen: + +.Result +[source, queryresult] +---- +(no changes, no records) +---- + +.Notification +[source] +---- +`CREATE CONSTRAINT sequels IF NOT EXISTS FOR ()-[e:SEQUEL_OF]-() REQUIRE (e.order) IS UNIQUE` has no effect. +`CONSTRAINT sequels FOR ()-[e:SEQUEL_OF]-() REQUIRE (e.order) IS UNIQUE` already exists. +---- + +====== + +.Create a relationship property uniqueness constraint when the same constraint with a different name already exists +====== + +.Create a constraint requiring all `SEQUEL_OF` relationships to have unique `order` properties +[source, cypher] +---- +CREATE CONSTRAINT new_sequels IF NOT EXISTS +FOR ()-[sequel:SEQUEL_OF]-() REQUIRE sequel.order IS UNIQUE +---- + +Because a constraint with a different name (`sequels`) on the same schema exists, nothing will happen: + +.Result +[source, queryresult] +---- +(no changes, no records) +---- + +.Notification +[source] +---- +`CREATE CONSTRAINT new_sequels IF NOT EXISTS FOR ()-[e:SEQUEL_OF]-() REQUIRE (e.order) IS UNIQUE` has no effect. +`CONSTRAINT sequels FOR ()-[e:SEQUEL_OF]-() REQUIRE (e.order) IS UNIQUE` already exists. +---- + +====== + +.Create a relationship property uniqueness constraint with the same name as an existing constraint of a different type +====== + +.Create a constraint requiring all `AUTHORED` relationships to have unique `name` properties +[source, cypher] +---- +CREATE CONSTRAINT author_name IF NOT EXISTS +FOR ()-[a:AUTHORED]-() REQUIRE a.name IS UNIQUE +---- + +Because a node property existence constraint named `author_name` already exists, nothing will happen: + +.Result +[source, queryresult] +---- +(no changes, no records) +---- + +.Notification +[source] +---- +`CREATE CONSTRAINT author_name IF NOT EXISTS FOR ()-[e:AUTHORED]-() REQUIRE (e.name) IS UNIQUE` has no effect. +`CONSTRAINT author_name FOR (e:Author) REQUIRE (e.name) IS NOT NULL` already exists. +---- + +====== + +[[create-an-already-existing-constraint]] +==== Creating an already existing constraint will fail + +Creating a constraint with the same name or on the same node label or relationship type and properties that are already constrained by a constraint of the same type will fail. +Property uniqueness and key constraints are also not allowed on the same schema. + +.Create a constraint identical to an existing constraint +====== + +.Create a constraint requiring all `SEQUEL_OF` relationships to have unique `order` properties, given an identical constraint already exists +[source, cypher, role=test-fail] +---- +CREATE CONSTRAINT sequels +FOR ()-[sequel:SEQUEL_OF]-() REQUIRE sequel.order IS UNIQUE +---- + +.Error message +[source, error] +---- +An equivalent constraint already exists, 'Constraint( id=5, name='sequels', type='RELATIONSHIP UNIQUENESS', schema=()-[:SEQUEL_OF {order}]-(), ownedIndex=4 )'. +---- + +[NOTE] +The constraint type will be updated to say `RELATIONSHIP PROPERTY UNIQUENESS` in a future version of Neo4j. + +====== + +.Create a constraint with a different name but on the same schema as an existing constraint +====== + +.Create a constraint requiring all `Book` nodes to have unique `isbn` properties, given that a constraint on that schema already exists +[source, cypher, role=test-fail] +---- +CREATE CONSTRAINT new_book_isbn +FOR (book:Book) REQUIRE book.isbn IS UNIQUE +---- + +.Error message +[source, error] +---- +Constraint already exists: Constraint( id=3, name='book_isbn', type='UNIQUENESS', schema=(:Book {isbn}), ownedIndex=2 ) +---- + +[NOTE] +The constraint type will be updated to say `NODE PROPERTY UNIQUENESS` in a future version of Neo4j. + +====== + +.Creating a constraint with the same name but on a different schema as an existing constraint +====== + +.Create a constraint requiring all `AUTHORED` relationships to have unique `name` properties, given that a constraint on a different schema with the same name already exists +[source, cypher, role=test-fail] +---- +CREATE CONSTRAINT author_name +FOR ()-[a:AUTHORED]-() REQUIRE a.name IS UNIQUE +---- + +.Error message +[source, error] +---- +There already exists a constraint called 'author_name'. +---- + +====== + +.Creating a property type constraint on a property when a property type constraint constraining the property to a different type already exist +====== + +.Create a constraint requiring `order` properties on `PART_OF` relationships to be of type `FLOAT`, given a constraint requiring the same properties to be of type `INTEGER` already exists +[source, cypher, role=test-fail] +---- +CREATE CONSTRAINT new_part_of +FOR ()-[part:PART_OF]-() REQUIRE part.order IS :: FLOAT +---- + + +.Error message +[source, error] +---- +Conflicting constraint already exists: Constraint( id=21, name='part_of', type='RELATIONSHIP PROPERTY TYPE', schema=()-[:PART_OF {order}]-(), propertyType=INTEGER ) +---- + +====== + +.Creating a node key constraint on the same schema as an existing property uniqueness constraint +====== + +.Create a node key constraint on the properties `title` and `publicationYear` on nodes with the `Book` label, when a property uniqueness constraint already exists on the same label and property combination +[source, cypher, role=test-fail] +---- +CREATE CONSTRAINT book_titles FOR (book:Book) REQUIRE (book.title, book.publicationYear) IS NODE KEY +---- + +.Error message +[source, error] +---- +Constraint already exists: Constraint( id=7, name='book_title_year', type='UNIQUENESS', schema=(:Book {title, publicationYear}), ownedIndex=6 ) +---- + +====== + +[[constraints-and-indexes]] +=== Constraints and indexes + +* xref:constraints/managing-constraints.adoc#constraints-and-backing-indexes[] +* xref:constraints/managing-constraints.adoc#create-constraint-with-index-provider[] +* xref:constraints/managing-constraints.adoc#constraint-failures-and-indexes[] + +[[constraints-and-backing-indexes]] +==== Constraints and backing indexes + +Property uniqueness constraints and key constraints are backed by xref:indexes/search-performance-indexes/managing-indexes.adoc#create-range-index[range indexes]. +This means that creating a property uniqueness or key constraint will create a range index with the same name, node label/relationship type and property combination as its owning constraint. +Single property constraints will create single property indexes and multiple property composite constraints will create xref:indexes/search-performance-indexes/using-indexes.adoc#composite-indexes[composite indexes]. + +[NOTE] +Indexes of the same index type, label/relationship type, and property combination cannot be added separately. +However, dropping a property uniqueness or key constraint will also drop its backing index. +If the backing index is still required, the index needs to be explicitly re-created. + +Property uniqueness and key constraints require an index because it allows the system to quickly check if a node with the same label and property value or a relationship with the same type and property value already exists. +Without an index, the system would need to scan all nodes with the same label, which would be slow and inefficient, especially as the graph grows. +The index makes these checks much faster by enabling direct lookups instead of scanning the entire graph. +Cypher will use the indexes with an owning constraint in the same way that it utilizes other search-performance indexes. +For more information about how indexes impact query performance, see xref:indexes/search-performance-indexes/using-indexes.adoc[]. + +These indexes are listed in the `owningConstraint` column returned by the xref:indexes/search-performance-indexes/managing-indexes.adoc#list-indexes[`SHOW INDEX`] command, and the `ownedIndex` column returned by the xref:constraints/managing-constraints.adoc#list-constraints[`SHOW CONSTRAINT`] command. + +.List constraints with backing indexes +====== + +.Query +[source, cypher, test-exclude-cols=id] +---- +SHOW CONSTRAINTS WHERE ownedIndex IS NOT NULL +---- + +.Result +[source, queryresult] +---- ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| id | name | type | entityType | labelsOrTypes | properties | ownedIndex | propertyType | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 21 | "actor_fullname" | "NODE_KEY" | "NODE" | ["Actor"] | ["firstname", "surname"] | "actor_fullname" | NULL | +| 3 | "book_isbn" | "UNIQUENESS" | "NODE" | ["Book"] | ["isbn"] | "book_isbn" | NULL | +| 7 | "book_title_year" | "UNIQUENESS" | "NODE" | ["Book"] | ["title", "publicationYear"] | "book_title_year" | NULL | +| 17 | "director_imdbId" | "NODE_KEY" | "NODE" | ["Director"] | ["imdbId"] | "director_imdbId" | NULL | +| 23 | "knows_since_how" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["KNOWS"] | ["since", "how"] | "knows_since_how" | NULL | +| 25 | "node_uniqueness_param" | "UNIQUENESS" | "NODE" | ["Book"] | ["prop1"] | "node_uniqueness_param" | NULL | +| 19 | "ownershipId" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["OWNS"] | ["ownershipId"] | "ownershipId" | NULL | +| 9 | "prequels" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["PREQUEL_OF"] | ["order", "author"] | "prequels" | NULL | +| 5 | "sequels" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["SEQUEL_OF"] | ["order"] | "sequels" | NULL | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +---- + +====== + +.List indexes with owning constraints +====== + +.Query +[source, cypher, test-exclude-cols=id] +---- +SHOW INDEXES WHERE owningConstraint IS NOT NULL +---- + +.Result +[source, queryresult] +---- ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| id | name | state | populationPercent | type | entityType | labelsOrTypes | properties | indexProvider | owningConstraint | lastRead | readCount | ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 20 | "actor_fullname" | "ONLINE" | 100.0 | "RANGE" | "NODE" | ["Actor"] | ["firstname", "surname"] | "range-1.0" | "actor_fullname" | 2024-10-07T12:12:51.893Z | 3 | +| 2 | "book_isbn" | "ONLINE" | 100.0 | "RANGE" | "NODE" | ["Book"] | ["isbn"] | "range-1.0" | "book_isbn" | 2024-10-07T11:58:09.252Z | 2 | +| 6 | "book_title_year" | "ONLINE" | 100.0 | "RANGE" | "NODE" | ["Book"] | ["title", "publicationYear"] | "range-1.0" | "book_title_year" | NULL | 0 | +| 16 | "director_imdbId" | "ONLINE" | 100.0 | "RANGE" | "NODE" | ["Director"] | ["imdbId"] | "range-1.0" | "director_imdbId" | NULL | 0 | +| 22 | "knows_since_how" | "ONLINE" | 100.0 | "RANGE" | "RELATIONSHIP" | ["KNOWS"] | ["since", "how"] | "range-1.0" | "knows_since_how" | 2024-10-07T12:12:51.894Z | 1 | +| 24 | "node_uniqueness_param" | "ONLINE" | 100.0 | "RANGE" | "NODE" | ["Book"] | ["prop1"] | "range-1.0" | "node_uniqueness_param" | NULL | 0 | +| 18 | "ownershipId" | "ONLINE" | 100.0 | "RANGE" | "RELATIONSHIP" | ["OWNS"] | ["ownershipId"] | "range-1.0" | "ownershipId" | NULL | 0 | +| 8 | "prequels" | "ONLINE" | 100.0 | "RANGE" | "RELATIONSHIP" | ["PREQUEL_OF"] | ["order", "author"] | "range-1.0" | "prequels" | NULL | 0 | +| 4 | "sequels" | "ONLINE" | 100.0 | "RANGE" | "RELATIONSHIP" | ["SEQUEL_OF"] | ["order"] | "range-1.0" | "sequels" | 2024-10-07T11:57:12.999Z | 1 | ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +---- + +====== + +[NOTE] +Property existence and property type constraints are not backed by indexes. + +[[create-constraint-with-index-provider]] +==== Creating constraints with an index provider + +Because property uniqueness and key constraints have backing indexes, an index provider can be provided when creating these constraints using the `OPTIONS` clause and the `indexProvider` option. + +The only valid value for the index provider is: + +* `range-1.0` label:default[] + + +.Create a node key constraint with a specified index provider +====== + +.Create a constraint requiring `Actor` nodes to have a unique `surname` property as a node key, specifying `range-1.0` as index provider +[source, cypher] +---- +CREATE CONSTRAINT constraint_with_provider +FOR (actor:Actor) REQUIRE actor.surname IS NODE KEY +OPTIONS { + indexProvider: 'range-1.0' +} +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +.Create a relationship property uniqueness constraint with a specified index provider +====== + +.Create a constraint requiring `SEQUEL_OF` relationships to have a unique combination of `order`, `seriesTitle`, and `number` properties, specifying `range-1.0` as index provider +[source, cypher] +---- +CREATE CONSTRAINT rel_constraint_with_options +FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.order, sequel.seriesTitle, sequel.number) IS UNIQUE +OPTIONS { + indexProvider: 'range-1.0' +} +---- + +.Result +[source, queryresult] +---- +Added 1 constraint. +---- + +====== + +There are no valid index configuration values for the constraint-backing range indexes. + +[[constraint-failures-and-indexes]] +==== Constraint failures and indexes + +Attempting to create any type of constraint with the same name as an existing index will fail. + +.Creating a node property type constraint with the same name as an existing index +====== + +.Create an index with the name `directors` +[source, cypher] +---- +CREATE INDEX directors FOR (director:Director) ON (director.name) +---- + +.Create a node property type constraint with the name `directors` +[source, cypher, role=test-fail] +---- +CREATE CONSTRAINT directors FOR (movie:Movie) REQUIRE movie.director IS :: STRING +---- + +.Error message +[source, error] +---- +There already exists an index called 'directors'. +---- + +====== + +Creating key or property uniqueness constraints on the same schema as an existing index will fail. + +.Creating a node property uniqueness constraint on the same schema as an existing index +====== + +.Create an index for `wordCount` properties on `Book` nodes +[source, cypher] +---- +CREATE INDEX book_word_count FOR (book:Book) ON (book.wordCount) +---- + +.Create a constraint requiring all `Book` nodes to have unique `wordCount` properties +[source, cypher, role=test-fail] +---- +CREATE CONSTRAINT word_count FOR (book:Book) REQUIRE book.wordCount IS UNIQUE +---- + +.Error message +[source, error] +---- +There already exists an index (:Book {wordCount}). +A constraint cannot be created until the index has been dropped. +---- + +====== + + +[[constraints-and-data-violation-scenarios]] +=== Constraints and data violation scenarios + +* xref:constraints/managing-constraints.adoc#create-data-that-violates-a-constraint[] +* xref:constraints/managing-constraints.adoc#removing-an-existing-constrained-property-will-fail[] +* xref:constraints/managing-constraints.adoc#modifying-property-constrained-property-will-fail[] +* xref:constraints/managing-constraints.adoc#fail-to-create-constraint-due-to-existing-data[] + +[[create-data-that-violates-a-constraint]] +==== Creating data that violates existing constraints will fail + +.Existing constraints preventing data creation +[cols="4", options="header"] +|=== +| Constraint type +| Create nodes and relationships without an existence constrained property +| Create nodes and relationships with non-unique properties/property combinations +| Create nodes and relationships with the wrong property type + +| *Property uniqueness constraint* +| +^| ❌ +| + +| *Property existence constraint* +^| ❌ +| +| + +| *Property type constraint* +| +| +^| ❌ + +| *Key constraint* +^| ❌ +^| ❌ +| + +|=== + + +.Create a node that violates a node property uniqueness constraint +====== + +.Create a `Book` node with an `isbn` property that already exists +[source, cypher, role=test-fail] +---- +CREATE (book:Book {isbn: '1449356265', title: 'Graph Databases'}) +---- + +.Error message +[source, error] +---- +Node(0) already exists with label `Book` and property `isbn` = '1449356265' +---- + +====== + +.Create a node that violates an existing node property existence constraint +====== + +.Create an `Author` node without a `name` property, given a property existence constraint on `:Author(name)` +[source, cypher, role=test-fail] +---- +CREATE (author:Author {surname: 'Austen'}) +---- + +.Error message +[source, error] +---- +Node(0) with label `Author` must have the property `name` +---- + +====== + +.Create a relationship that violates an existing relationship property type constraint +====== + + +.Create a `PART_OF` relationship with a `STRING` `order` property, given a property type constraint on the relationship type `PART_OF` restricting the `order` property to `INTEGER` values +[source, cypher, role=test-fail] +---- +MATCH (movie:Movie {title:'Iron Man'}), (franchise:Franchise {name:'MCU'}) +CREATE (movie)-[part:PART_OF {order: '1'}]->(franchise) +---- + +.Error message +[source, error] +---- +Relationship(0) with type `PART_OF` has property `order` of wrong type `String`. Allowed types: INTEGER +---- + +====== + + +.Create a node that violates an existing node key constraint +====== + +.Create an `Actor` node without a `firstname` property, given a node key constraint on `:Actor(firstname, surname)` +[source, cypher, role=test-fail] +---- +CREATE (actor:Actor {surname: 'Wood'}) +---- + +.Error message +[source, error] +---- +Node(0) with label `Actor` must have the properties (`firstname`, `surname`) +---- + +====== + +[[removing-an-existing-constrained-property-will-fail]] +==== Removing existence and key constrained properties will fail + +.Remove a node property existence constrained property +====== + +.Remove the `name` property from an existing `Author` node, given a property existence constraint on `:Author(name)` +[source, cypher, role=test-fail] +---- +MATCH (author:Author {name: 'Virginia Woolf'}) +REMOVE author.name +---- + +.Error message +[source, error] +---- +Node(0) with label `Author` must have the property `name` +---- + +====== + + +.Remove a node key constrained property +====== + +.Remove the `firstname` property from an existing node `Actor`, given a node key constraint on `:Actor(firstname, surname)` +[source, cypher, role=test-fail] +---- +MATCH (actor:Actor {firstname: 'Keanu', surname: 'Reeves'}) +REMOVE actor.firstname +---- + +.Error message +[source, error] +---- +Node(0) with label `Actor` must have the properties (`firstname`, `surname`) +---- + +====== + +[[modifying-property-constrained-property-will-fail]] +==== Modifying type constrained properties will fail + +.Modify a type constrained property +====== + +.Modify the `title` for the `Movie` 'Iron Man' to an `INTEGER` value, given a constraint requiring `title` properties to be of type `STRING` +[source, cypher, role=test-fail] +---- +MATCH (m:Movie {title: 'Iron Man'}) +SET m.title = 13 +---- + +.Error message +[source, error] +---- +Node(9) with label `Movie` required the property `title` to be of type `STRING`, but was of type `INTEGER`. +---- + +====== + + +[[fail-to-create-constraint-due-to-existing-data]] +==== Creating constraints when there exists conflicting data will fail + +.Existing data preventing constraint creation +[cols="4", options="header"] +|=== +| Constraint type +| Non-existing property +| Non-unique property/property combination +| Property of wrong type + +| *Property uniqueness constraint* +| +^| ❌ +| + +| *Property existence constraint* +^| ❌ +| +| + +| *Property type constraint* +| +| +^| ❌ + +| *Key constraint* +^| ❌ +^| ❌ +| + +|=== + +.Create a node property uniqueness constraint when conflicting nodes exist +====== + +.Create two `Book` nodes with the same `name` property value +[source, cypher] +---- +CREATE (:Book {isbn: '9780393972832', title: 'Moby Dick'}), + (:Book {isbn: '9780763630188', title: 'Moby Dick'}) +---- + + +.Create a constraint requiring `Book` nodes to have unique `title` properties, when there already exists two `Book` nodes with the same `title` +[source, cypher, role=test-fail] +---- +CREATE CONSTRAINT book_title FOR (book:Book) REQUIRE book.title IS UNIQUE +---- + +In this case, the constraint cannot be created because it is in conflict with the existing graph. +Either use xref:indexes/search-performance-indexes/managing-indexes.adoc[indexes] instead, or remove/correct the offending nodes and then re-apply the constraint. + +.Error message +[source, error] +---- +Unable to create Constraint( name='book_title', type='UNIQUENESS', schema=(:Book {title}) ): +Both Node(0) and Node(1) have the label `Book` and property `title` = 'Moby Dick' +---- + +The constraint creation fails on the first offending nodes that are found. +This does not guarantee that there are no other offending nodes in the graph. +Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. + +.Find all offending nodes with the non-unique property values for the constraint above +[source, cypher] +---- +MATCH (book1:Book), (book2:Book) +WHERE book1.title = book2.title AND NOT book1 = book2 +RETURN book1, book2 +---- + +====== + + +.Create a relationship property existence constraint when conflicting relationships exist +====== + +.Create a constraint requiring all `WROTE` relationships to have a `language` property, when there already exists a `WROTE` relationship without a `language` property +[source, cypher, role=test-fail] +---- +CREATE CONSTRAINT wrote_language FOR ()-[wrote:WROTE]-() REQUIRE wrote.language IS NOT NULL +---- + +In this case, the constraint cannot be created because it is in conflict with the existing graph. +Remove or correct the offending relationships and then re-apply the constraint. + +.Error message +[source, error] +---- +Unable to create Constraint( type='RELATIONSHIP PROPERTY EXISTENCE', schema=()-[:WROTE {language}]-() ): +Relationship(0) with type `WROTE` must have the property `language`. Note that only the first found violation is shown. +---- + +The constraint creation fails on the first offending relationship that is found. +This does not guarantee that there are no other offending relationships in the graph. +Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. + + +.Find all offending relationships missing the property for the constraint above +[source, cypher] +---- +MATCH ()-[wrote:WROTE]-() +WHERE wrote.language IS NULL +RETURN wrote +---- + +====== + +.Generic `MATCH` queries to find the properties preventing the creation of particular constraints: +[options="header", cols="1,1m"] +|=== +| Constraint +| Query + +| Node property uniqueness constraint +a| +[source] +---- +MATCH (n1:Label), (n2:Label) +WHERE n1.prop = n2.prop AND NOT n1 = n2 +RETURN n1, n2 +---- + +| Relationship property uniqueness constraint +a| +[source] +---- +MATCH ()-[r1:REL_TYPE]->(), ()-[r2:REL_TYPE]->() +WHERE r1.prop = r2.prop AND NOT r1 = r2 +RETURN r1, r2 +---- + +| Node property existence constraint +a| +[source] +---- +MATCH (n:Label) +WHERE n.prop IS NULL +RETURN n +---- + +| Relationship property existence constraint +a| +[source] +---- +MATCH ()-[r:REL_TYPE]->() +WHERE r.prop IS NULL +RETURN r +---- + +| Node property type constraint +a| +[source] +---- +MATCH (n:Label) +WHERE n.prop IS NOT :: +RETURN n +---- + +| Relationship property type constraint +a| +[source] +---- +MATCH ()-[r:REL_TYPE]->() +WHERE r.prop IS NOT :: +RETURN r +---- + +| Node key constraint +a| +[source] +---- +MATCH (n1:Label), (n2:Label) +WHERE n1.prop = n2.prop AND NOT n1 = n2 +UNWIND [n1, n2] AS node +RETURN node, 'non-unique' AS reason +UNION +MATCH (n:Label) +WHERE n.prop IS NULL +RETURN n AS node, 'non-existing' AS reason +---- + +| Relationship key constraint +a| +[source] +---- +MATCH ()-[r1:REL_TYPE]->(), ()-[r2:REL_TYPE]->() +WHERE r1.prop = r2.prop AND NOT r1 = r2 +UNWIND [r1, r2] AS relationship +RETURN relationship, 'non-unique' AS reason +UNION +MATCH ()-[r:REL_TYPE]->() +WHERE r.prop IS NULL +RETURN r AS relationship, 'non-existing' AS reason +---- + +|=== + +[[list-constraints]] +== SHOW CONSTRAINTS + +To list all constraints with the default output columns, use `SHOW CONSTRAINTS`. +If all columns are required, use `SHOW CONSTRAINTS YIELD *`. +For the full command syntax to list constraints, see xref:constraints/syntax.adoc#list-constraints[Syntax -> SHOW CONSTRAINTS]. + +One of the output columns from `SHOW CONSTRAINTS` is the name of the constraint. +This can be used to drop the constraint with the xref::constraints/managing-constraints.adoc#drop-constraint[`DROP CONSTRAINT` command]. + +[NOTE] +Listing constraints requires the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/database-administration/#access-control-database-administration-constraints[`SHOW CONSTRAINTS` privilege]. + +.List all constraints with default output columns +====== + +.Query +[source, cypher, test-exclude-cols=id] +---- +SHOW CONSTRAINTS +---- + +.Result +[source, queryresult] +---- ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| id | name | type | entityType | labelsOrTypes | properties | ownedIndex | propertyType | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 21 | "actor_fullname" | "NODE_KEY" | "NODE" | ["Actor"] | ["firstname", "surname"] | "actor_fullname" | NULL | +| 10 | "author_name" | "NODE_PROPERTY_EXISTENCE" | "NODE" | ["Author"] | ["name"] | NULL | NULL | +| 3 | "book_isbn" | "UNIQUENESS" | "NODE" | ["Book"] | ["isbn"] | "book_isbn" | NULL | +| 7 | "book_title_year" | "UNIQUENESS" | "NODE" | ["Book"] | ["title", "publicationYear"] | "book_title_year" | NULL | +| 28 | "constraint_with_provider" | "NODE_KEY" | "NODE" | ["Actor"] | ["surname"] | "constraint_with_provider" | NULL | +| 17 | "director_imdbId" | "NODE_KEY" | "NODE" | ["Director"] | ["imdbId"] | "director_imdbId" | NULL | +| 23 | "knows_since_how" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["KNOWS"] | ["since", "how"] | "knows_since_how" | NULL | +| 14 | "movie_tagline" | "NODE_PROPERTY_TYPE" | "NODE" | ["Movie"] | ["tagline"] | NULL | "STRING | LIST" | +| 12 | "movie_title" | "NODE_PROPERTY_TYPE" | "NODE" | ["Movie"] | ["title"] | NULL | "STRING" | +| 25 | "node_uniqueness_param" | "UNIQUENESS" | "NODE" | ["Book"] | ["prop1"] | "node_uniqueness_param" | NULL | +| 19 | "ownershipId" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["OWNS"] | ["ownershipId"] | "ownershipId" | NULL | +| 13 | "part_of" | "RELATIONSHIP_PROPERTY_TYPE" | "RELATIONSHIP" | ["PART_OF"] | ["order"] | NULL | "INTEGER" | +| 15 | "part_of_tags" | "RELATIONSHIP_PROPERTY_TYPE" | "RELATIONSHIP" | ["PART_OF"] | ["tags"] | NULL | "STRING | LIST" | +| 9 | "prequels" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["PREQUEL_OF"] | ["order", "author"] | "prequels" | NULL | +| 30 | "rel_constraint_with_options" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["SEQUEL_OF"] | ["order", "seriesTitle", "number"] | "rel_constraint_with_options" | NULL | +| 26 | "rel_exist_param" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["published"] | NULL | NULL | +| 5 | "sequels" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["SEQUEL_OF"] | ["order"] | "sequels" | NULL | +| 11 | "wrote_year" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["year"] | NULL | NULL | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +---- + +====== + +.List all constraints with full details +====== + +To return the full details of the constraints on a database, use `SHOW CONSTRAINTS YIELD *` + +.List all constraints with `YIELD *` +[source, cypher, test-exclude-cols=id] +---- +SHOW CONSTRAINTS YIELD * +---- + +.Result +[source, queryresult] +---- ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 21 | "actor_fullname" | "NODE_KEY" | "NODE" | ["Actor"] | ["firstname", "surname"] | "actor_fullname" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `actor_fullname` FOR (n:`Actor`) REQUIRE (n.`firstname`, n.`surname`) IS NODE KEY" | +| 10 | "author_name" | "NODE_PROPERTY_EXISTENCE" | "NODE" | ["Author"] | ["name"] | NULL | NULL | NULL | "CREATE CONSTRAINT `author_name` FOR (n:`Author`) REQUIRE (n.`name`) IS NOT NULL" | +| 3 | "book_isbn" | "UNIQUENESS" | "NODE" | ["Book"] | ["isbn"] | "book_isbn" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `book_isbn` FOR (n:`Book`) REQUIRE (n.`isbn`) IS UNIQUE" | +| 7 | "book_title_year" | "UNIQUENESS" | "NODE" | ["Book"] | ["title", "publicationYear"] | "book_title_year" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `book_title_year` FOR (n:`Book`) REQUIRE (n.`title`, n.`publicationYear`) IS UNIQUE" | +| 28 | "constraint_with_provider" | "NODE_KEY" | "NODE" | ["Actor"] | ["surname"] | "constraint_with_provider" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `constraint_with_provider` FOR (n:`Actor`) REQUIRE (n.`surname`) IS NODE KEY" | +| 17 | "director_imdbId" | "NODE_KEY" | "NODE" | ["Director"] | ["imdbId"] | "director_imdbId" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `director_imdbId` FOR (n:`Director`) REQUIRE (n.`imdbId`) IS NODE KEY" | +| 23 | "knows_since_how" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["KNOWS"] | ["since", "how"] | "knows_since_how" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `knows_since_how` FOR ()-[r:`KNOWS`]-() REQUIRE (r.`since`, r.`how`) IS RELATIONSHIP KEY" | +| 14 | "movie_tagline" | "NODE_PROPERTY_TYPE" | "NODE" | ["Movie"] | ["tagline"] | NULL | "STRING | LIST" | NULL | "CREATE CONSTRAINT `movie_tagline` FOR (n:`Movie`) REQUIRE (n.`tagline`) IS :: STRING | LIST" | +| 12 | "movie_title" | "NODE_PROPERTY_TYPE" | "NODE" | ["Movie"] | ["title"] | NULL | "STRING" | NULL | "CREATE CONSTRAINT `movie_title` FOR (n:`Movie`) REQUIRE (n.`title`) IS :: STRING" | +| 25 | "node_uniqueness_param" | "UNIQUENESS" | "NODE" | ["Book"] | ["prop1"] | "node_uniqueness_param" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `node_uniqueness_param` FOR (n:`Book`) REQUIRE (n.`prop1`) IS UNIQUE" | +| 19 | "ownershipId" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["OWNS"] | ["ownershipId"] | "ownershipId" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `ownershipId` FOR ()-[r:`OWNS`]-() REQUIRE (r.`ownershipId`) IS RELATIONSHIP KEY" | +| 13 | "part_of" | "RELATIONSHIP_PROPERTY_TYPE" | "RELATIONSHIP" | ["PART_OF"] | ["order"] | NULL | "INTEGER" | NULL | "CREATE CONSTRAINT `part_of` FOR ()-[r:`PART_OF`]-() REQUIRE (r.`order`) IS :: INTEGER" | +| 15 | "part_of_tags" | "RELATIONSHIP_PROPERTY_TYPE" | "RELATIONSHIP" | ["PART_OF"] | ["tags"] | NULL | "STRING | LIST" | NULL | "CREATE CONSTRAINT `part_of_tags` FOR ()-[r:`PART_OF`]-() REQUIRE (r.`tags`) IS :: STRING | LIST" | +| 9 | "prequels" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["PREQUEL_OF"] | ["order", "author"] | "prequels" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `prequels` FOR ()-[r:`PREQUEL_OF`]-() REQUIRE (r.`order`, r.`author`) IS UNIQUE" | +| 30 | "rel_constraint_with_options" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["SEQUEL_OF"] | ["order", "seriesTitle", "number"] | "rel_constraint_with_options" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `rel_constraint_with_options` FOR ()-[r:`SEQUEL_OF`]-() REQUIRE (r.`order`, r.`seriesTitle`, r.`number`) IS UNIQUE" | +| 26 | "rel_exist_param" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["published"] | NULL | NULL | NULL | "CREATE CONSTRAINT `rel_exist_param` FOR ()-[r:`WROTE`]-() REQUIRE (r.`published`) IS NOT NULL" | +| 5 | "sequels" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["SEQUEL_OF"] | ["order"] | "sequels" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `sequels` FOR ()-[r:`SEQUEL_OF`]-() REQUIRE (r.`order`) IS UNIQUE" | +| 11 | "wrote_year" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["year"] | NULL | NULL | NULL | "CREATE CONSTRAINT `wrote_year` FOR ()-[r:`WROTE`]-() REQUIRE (r.`year`) IS NOT NULL" | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +---- +====== + +[NOTE] +The `type` column returns `UNIQUENESS` for the node property uniqueness constraint and `RELATIONSHIP_UNIQUENESS` for the relationship property uniqueness constraint. +This will be updated in a future version of Neo4j. +Node property uniqueness constraints will be updated to `NODE_PROPERTY_UNIQUENESS` and relationship property uniqueness constraints to `RELATIONSHIP_PROPERTY_UNIQUENESS`. + +[[list-constraints-with-filtering]] +=== Listing constraints with filtering + +The `SHOW CONSTRAINTS` command can be filtered in various ways. +The filtering of rows can be done using constraint type keywords or a `WHERE` clause, while filtering of columns is achieved by specifying the desired columns in a `YIELD` clause. + +.List only specific constraint types +====== + +.List only key constraints +[source, cypher, test-exclude-cols=id] +---- +SHOW KEY CONSTRAINTS +---- + +.Result +[source, queryresult] +---- ++--------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| id | name | type | entityType | labelsOrTypes | properties | ownedIndex | propertyType | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 21 | "actor_fullname" | "NODE_KEY" | "NODE" | ["Actor"] | ["firstname", "surname"] | "actor_fullname" | NULL | +| 28 | "constraint_with_provider" | "NODE_KEY" | "NODE" | ["Actor"] | ["surname"] | "constraint_with_provider" | NULL | +| 17 | "director_imdbId" | "NODE_KEY" | "NODE" | ["Director"] | ["imdbId"] | "director_imdbId" | NULL | +| 23 | "knows_since_how" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["KNOWS"] | ["since", "how"] | "knows_since_how" | NULL | +| 19 | "ownershipId" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["OWNS"] | ["ownershipId"] | "ownershipId" | NULL | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------+ +---- + +For a full list of all the constraint types (and synonyms) available in this command see xref:constraints/syntax.adoc#list-constraints[Syntax -> SHOW CONSTRAINTS]. + +====== + + +.Filtering constraints using the `WHERE` clause +====== + +.List only constraints with a `RELATIONSHIP` `entityType` +[source, cypher, test-exclude-cols=id] +---- +SHOW CONSTRAINTS +WHERE entityType = 'RELATIONSHIP' +---- + +.Result +[source, queryresult] +---- ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| id | name | type | entityType | labelsOrTypes | properties | ownedIndex | propertyType | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 23 | "knows_since_how" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["KNOWS"] | ["since", "how"] | "knows_since_how" | NULL | +| 19 | "ownershipId" | "RELATIONSHIP_KEY" | "RELATIONSHIP" | ["OWNS"] | ["ownershipId"] | "ownershipId" | NULL | +| 13 | "part_of" | "RELATIONSHIP_PROPERTY_TYPE" | "RELATIONSHIP" | ["PART_OF"] | ["order"] | NULL | "INTEGER" | +| 15 | "part_of_tags" | "RELATIONSHIP_PROPERTY_TYPE" | "RELATIONSHIP" | ["PART_OF"] | ["tags"] | NULL | "STRING | LIST" | +| 9 | "prequels" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["PREQUEL_OF"] | ["order", "author"] | "prequels" | NULL | +| 30 | "rel_constraint_with_options" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["SEQUEL_OF"] | ["order", "seriesTitle", "number"] | "rel_constraint_with_options" | NULL | +| 26 | "rel_exist_param" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["published"] | NULL | NULL | +| 5 | "sequels" | "RELATIONSHIP_UNIQUENESS" | "RELATIONSHIP" | ["SEQUEL_OF"] | ["order"] | "sequels" | NULL | +| 11 | "wrote_year" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "RELATIONSHIP" | ["WROTE"] | ["year"] | NULL | NULL | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +---- + +====== + + +.Returning specific columns for all constraints +====== + +It is possible to return only specific columns of the available constraints using the `YIELD` clause: + +.List only the `name`, `type`, and `createStatement` columns +[source, cypher, test-exclude-cols=id] +---- +SHOW CONSTRAINTS +YIELD name, type, createStatement +---- + +.Result +[source, queryresult] +---- ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| name | type | createStatement | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| "actor_fullname" | "NODE_KEY" | "CREATE CONSTRAINT `actor_fullname` FOR (n:`Actor`) REQUIRE (n.`firstname`, n.`surname`) IS NODE KEY" | +| "author_name" | "NODE_PROPERTY_EXISTENCE" | "CREATE CONSTRAINT `author_name` FOR (n:`Author`) REQUIRE (n.`name`) IS NOT NULL" | +| "book_isbn" | "UNIQUENESS" | "CREATE CONSTRAINT `book_isbn` FOR (n:`Book`) REQUIRE (n.`isbn`) IS UNIQUE" | +| "book_title_year" | "UNIQUENESS" | "CREATE CONSTRAINT `book_title_year` FOR (n:`Book`) REQUIRE (n.`title`, n.`publicationYear`) IS UNIQUE" | +| "constraint_with_provider" | "NODE_KEY" | "CREATE CONSTRAINT `constraint_with_provider` FOR (n:`Actor`) REQUIRE (n.`surname`) IS NODE KEY" | +| "director_imdbId" | "NODE_KEY" | "CREATE CONSTRAINT `director_imdbId` FOR (n:`Director`) REQUIRE (n.`imdbId`) IS NODE KEY" | +| "knows_since_how" | "RELATIONSHIP_KEY" | "CREATE CONSTRAINT `knows_since_how` FOR ()-[r:`KNOWS`]-() REQUIRE (r.`since`, r.`how`) IS RELATIONSHIP KEY" | +| "movie_tagline" | "NODE_PROPERTY_TYPE" | "CREATE CONSTRAINT `movie_tagline` FOR (n:`Movie`) REQUIRE (n.`tagline`) IS :: STRING | LIST" | +| "movie_title" | "NODE_PROPERTY_TYPE" | "CREATE CONSTRAINT `movie_title` FOR (n:`Movie`) REQUIRE (n.`title`) IS :: STRING" | +| "node_uniqueness_param" | "UNIQUENESS" | "CREATE CONSTRAINT `node_uniqueness_param` FOR (n:`Book`) REQUIRE (n.`prop1`) IS UNIQUE" | +| "ownershipId" | "RELATIONSHIP_KEY" | "CREATE CONSTRAINT `ownershipId` FOR ()-[r:`OWNS`]-() REQUIRE (r.`ownershipId`) IS RELATIONSHIP KEY" | +| "part_of" | "RELATIONSHIP_PROPERTY_TYPE" | "CREATE CONSTRAINT `part_of` FOR ()-[r:`PART_OF`]-() REQUIRE (r.`order`) IS :: INTEGER" | +| "part_of_tags" | "RELATIONSHIP_PROPERTY_TYPE" | "CREATE CONSTRAINT `part_of_tags` FOR ()-[r:`PART_OF`]-() REQUIRE (r.`tags`) IS :: STRING | LIST" | +| "prequels" | "RELATIONSHIP_UNIQUENESS" | "CREATE CONSTRAINT `prequels` FOR ()-[r:`PREQUEL_OF`]-() REQUIRE (r.`order`, r.`author`) IS UNIQUE" | +| "rel_constraint_with_options" | "RELATIONSHIP_UNIQUENESS" | "CREATE CONSTRAINT `rel_constraint_with_options` FOR ()-[r:`SEQUEL_OF`]-() REQUIRE (r.`order`, r.`seriesTitle`, r.`number`) IS UNIQUE" | +| "rel_exist_param" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "CREATE CONSTRAINT `rel_exist_param` FOR ()-[r:`WROTE`]-() REQUIRE (r.`published`) IS NOT NULL" | +| "sequels" | "RELATIONSHIP_UNIQUENESS" | "CREATE CONSTRAINT `sequels` FOR ()-[r:`SEQUEL_OF`]-() REQUIRE (r.`order`) IS UNIQUE" | +| "wrote_year" | "RELATIONSHIP_PROPERTY_EXISTENCE" | "CREATE CONSTRAINT `wrote_year` FOR ()-[r:`WROTE`]-() REQUIRE (r.`year`) IS NOT NULL" | ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +---- + +====== + + +[[list-constraints-result-columns]] +=== Result columns for listing constraints + +.Listing constraints output +[options="header", width="100%", cols="4m,6a,2m"] +|=== +| Column | Description | Type + +| id +| The id of the constraint. label:default-output[] +| INTEGER + +| name +| Name of the constraint (explicitly set by the user or automatically assigned). label:default-output[] +| STRING + +| type +| The ConstraintType of this constraint (`UNIQUENESS` (node uniqueness), `RELATIONSHIP_UNIQUENESS`, `NODE_PROPERTY_EXISTENCE`, `RELATIONSHIP_PROPERTY_EXISTENCE`, `NODE_PROPERTY_TYPE`, `RELATIONSHIP_PROPERTY_TYPE`, `NODE_KEY`, or `RELATIONSHIP_KEY`). label:default-output[] + +[NOTE] +`UNIQUENESS` and `RELATIONSHIP_UNIQUENESS` will be updated to say `NODE_PROPERTY_UNIQUENESS` and `RELATIONSHIP_PROPERTY_UNIQUENESS` respectively in a future version of Neo4j. +| STRING + +| entityType +| Type of entities this constraint represents (`NODE` or `RELATIONSHIP`). label:default-output[] +| STRING + +| labelsOrTypes +| The labels or relationship types of this constraint. +The list returned will only include a single value (the name of the constrained node label or relationship type). label:default-output[] +| LIST + +| properties +| The properties of this constraint. label:default-output[] +| LIST + +| ownedIndex +| The name of the index associated with the constraint or `null`, in case no index is associated with it. label:default-output[] +| STRING + +| propertyType +| The property type the property is restricted to for property type constraints, or `null` for the other constraints. +label:default-output[] label:new[Introduced in 5.9] +| STRING + +| options +| The options passed to `CREATE` command, for the index associated to the constraint, or `null` if no index is associated with the constraint. +| MAP + +| createStatement +| Statement used to create the constraint. +| STRING + +|=== + +[[drop-constraint]] +== DROP CONSTRAINT + +Constraints are dropped using the `DROP CONSTRAINT` command. +For the full command syntax to drop constraints, see xref:constraints/syntax.adoc#drop-constraint[Syntax -> DROP CONSTRAINT]. + +[NOTE] +Dropping a constraint requires the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/database-administration/#access-control-database-administration-constraints[`DROP CONSTRAINT` privilege]. + +[[drop-constraint-by-name]] +=== Drop a constraint by name + +A constraint can be dropped using the name with the `DROP CONSTRAINT constraint_name` command. +It is the same command for all constraint types. +The name of the constraint can be found using the xref:constraints/managing-constraints.adoc#list-constraints[`SHOW CONSTRAINTS` command], given in the output column `name`. + +.Drop a constraint by name +====== + +.Drop the constraint `book_isbn` +[source, cypher] +---- +DROP CONSTRAINT book_isbn +---- + +.Result +[source, queryresult] +---- +Removed 1 constraint. +---- + +====== + +[role=label--new-5.16] +[[drop-constraint-with-parameter]] +=== Drop a constraint with a parameter + +Constraints can be dropped with a parameterized name. + +.Drop a constraint using a parameter +====== + +.Parameters +[source, parameters] +---- +{ + "name": "actor_fullname" +} +---- + +.Drop a constraint with a parameterized name +[source, cypher] +---- +DROP CONSTRAINT $name +---- + +.Result +[source, queryresult] +---- +Removed 1 constraint. +---- + +====== + +[[drop-constraint-nonexisting-constraint]] +=== Drop a non-existing constraint + +If it is uncertain if any constraint with a given name exists and you want to drop it if it does but not get an error should it not, use `IF EXISTS`. +This will ensure that no error is thrown. +As of Neo4j 5.17, an informational notification is returned stating that the constraint does not exist. + +.Drop a non-existing constraint +====== + +.Drop the non-existing constraint `missing_constraint_name` +[source, cypher] +---- +DROP CONSTRAINT missing_constraint_name IF EXISTS +---- + +.Result +[source, queryresult] +---- +(no changes, no records) +---- + +.Notification +[source] +---- +`DROP CONSTRAINT missing_constraint_name IF EXISTS` has no effect. `missing_constraint_name` does not exist. +---- + +====== \ No newline at end of file diff --git a/modules/ROOT/pages/constraints/syntax.adoc b/modules/ROOT/pages/constraints/syntax.adoc index 1a1f5a6f9..1267b5ba9 100644 --- a/modules/ROOT/pages/constraints/syntax.adoc +++ b/modules/ROOT/pages/constraints/syntax.adoc @@ -4,13 +4,21 @@ = Syntax :check-mark: icon:check[] +This page contains the syntax for creating, listing, and dropping the constraints available in Neo4j. + +More details about the syntax can be found in the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/syntax/[Operations Manual -> Cypher syntax for administration commands]. + [[constraints-syntax-create]] -== Syntax for creating constraints +== CREATE CONSTRAINT -Best practice when creating a constraint is to give the constraint a name. +Constraints are created with the `CREATE CONSTRAINT` command. +When creating a constraint, it is recommended to provide a constraint name. This name must be unique among both indexes and constraints. If a name is not explicitly given, a unique name will be auto-generated. +[NOTE] +Creating a constraint requires the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/database-administration/#access-control-database-administration-constraints[`CREATE CONSTRAINT` privilege]. + The `CREATE CONSTRAINT` command is optionally idempotent. This means its default behavior is to throw an error if an attempt is made to create the same constraint twice. With the `IF NOT EXISTS` flag, no error is thrown and nothing happens should a constraint with the same name or same schema and constraint type already exist. @@ -22,17 +30,11 @@ For constraints that are backed by an index, the index provider for the backing Only one valid value exists for the index provider, `range-1.0`, which is the default value. There is no supported index configuration for range indexes. -[NOTE] -==== -Creating a constraint requires the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/database-administration/#access-control-database-administration-constraints[`CREATE CONSTRAINT` privilege]. -==== +[[create-property-uniqueness-constraints]] +=== Create property uniqueness constraints -[[constraints-syntax-create-node-unique]] -=== Node property uniqueness constraint - -This command creates a property uniqueness constraint on nodes with the specified label and properties. - -[source, syntax, role="noheader", indent=0] +.Syntax for creating a node property uniqueness constraint on a single property +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR (n:LabelName) @@ -40,7 +42,8 @@ REQUIRE n.propertyName IS [NODE] UNIQUE [OPTIONS "{" option: value[, ...] "}"] ---- -[source, syntax, role="noheader", indent=0] +.Syntax for creating a composite node property uniqueness constraint on multiple properties +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR (n:LabelName) @@ -48,15 +51,8 @@ REQUIRE (n.propertyName_1, ..., n.propertyName_n) IS [NODE] UNIQUE [OPTIONS "{" option: value[, ...] "}"] ---- -Index provider can be specified using the `OPTIONS` clause. - -[role=label--new-5.7] -[[constraints-syntax-create-rel-unique]] -=== Relationship property uniqueness constraint - -This command creates a property uniqueness constraint on relationships with the specified relationship type and properties. - -[source, syntax, role="noheader", indent=0] +.Syntax for creating a relationship property uniqueness constraint on a single property label:new[Introduced in 5.7] +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR ()-"["r:RELATIONSHIP_TYPE"]"-() @@ -64,7 +60,8 @@ REQUIRE r.propertyName IS [REL[ATIONSHIP]] UNIQUE [OPTIONS "{" option: value[, ...] "}"] ---- -[source, syntax, role="noheader", indent=0] +.Syntax for creating a composite relationship property uniqueness constraint on multiple properties label:new[Introduced in 5.7] +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR ()-"["r:RELATIONSHIP_TYPE"]"-() @@ -72,15 +69,17 @@ REQUIRE (r.propertyName_1, ..., r.propertyName_n) IS [REL[ATIONSHIP]] UNIQUE [OPTIONS "{" option: value[, ...] "}"] ---- -Index provider can be specified using the `OPTIONS` clause. +An index provider can be specified using the `OPTIONS` clause. -[role=label--enterprise-edition] -[[constraints-syntax-create-node-exists]] -=== Node property existence constraint +For examples on how to create property uniqueness constraints, see xref:constraints/managing-constraints.adoc#create-property-uniqueness-constraints[Create, show, and drop constraints -> Create property uniqueness constraint]. +Property uniqueness constraints are xref:constraints/managing-constraints.adoc#constraints-and-indexes[index-backed]. -This command creates a property existence constraint on nodes with the specified label and property. +[role=label--enterprise-edition] +[[create-property-existence-constraints]] +=== Create property existence constraints -[source, syntax, role="noheader", indent=0] +.Syntax for creating a node property existence constraint +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR (n:LabelName) @@ -88,19 +87,8 @@ REQUIRE n.propertyName IS NOT NULL [OPTIONS "{" "}"] ---- -[NOTE] -==== -There are no supported `OPTIONS` values for existence constraints, but an empty options map is allowed for consistency. -==== - - -[role=label--enterprise-edition] -[[constraints-syntax-create-rel-exists]] -=== Relationship property existence constraint - -This command creates a property existence constraint on relationships with the specified relationship type and property. - -[source, syntax, role="noheader", indent=0] +.Syntax for creating a relationship property existence constraint +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR ()-"["r:RELATIONSHIP_TYPE"]"-() @@ -108,18 +96,16 @@ REQUIRE r.propertyName IS NOT NULL [OPTIONS "{" "}"] ---- -[NOTE] -==== -There are no supported `OPTIONS` values for existence constraints, but an empty options map is allowed for consistency. -==== +There are no supported `OPTIONS` values for property existence constraints, but an empty options map is allowed for consistency. -[role=label--enterprise-edition label--new-5.9] -[[constraints-syntax-create-node-prop-type]] -=== Node property type constraint +For examples on how to create property existence constraints, see xref:constraints/managing-constraints.adoc#create-property-existence-constraints[Create, show, and drop constraints -> Create property existence constraints]. -This command creates a property type constraint on nodes with the specified label and property. +[role=label--enterprise-edition label--new-5.9] +[[create-property-type-constraints]] +=== Create property type constraints -[source, syntax, role="noheader", indent=0] +.Syntax for creating a node property type constraint +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR (n:LabelName) @@ -127,49 +113,8 @@ REQUIRE n.propertyName {[IS] :: | IS TYPED} [OPTIONS "{" "}"] ---- -The three variations of the expression, `IS ::`, `::`, and `IS TYPED` are syntactic synonyms for the same expression. -The preferred syntax is the `IS ::` variant. - -Where `` is one of the following property types: - -* `BOOLEAN` -* `STRING` -* `INTEGER` -* `FLOAT` -* `DATE` -* `LOCAL TIME` -* `ZONED TIME` -* `LOCAL DATETIME` -* `ZONED DATETIME` -* `DURATION` -* `POINT` -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* `LIST` label:new[Introduced in 5.10] -* Any closed dynamic union of the above types, e.g. `INTEGER | FLOAT | STRING`. label:new[Introduced in 5.11] - -Allowed syntax variations of these types are listed xref::values-and-types/property-structural-constructed.adoc#types-synonyms[here]. - -[NOTE] -==== -There are no supported `OPTIONS` values for property type constraints, but an empty options map is allowed for consistency. -==== - -[role=label--enterprise-edition label--new-5.9] -[[constraints-syntax-create-rel-prop-type]] -=== Relationship property type constraint - -This command creates a property type constraint on relationships with the specified relationship type and property. - -[source, syntax, role="noheader", indent=0] +.Syntax for creating a relationship property type constraint +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR ()-"["r:RELATIONSHIP_TYPE"]"-() @@ -206,20 +151,19 @@ Where `` is one of the following property types: * `LIST` label:new[Introduced in 5.10] * Any closed dynamic union of the above types, e.g. `INTEGER | FLOAT | STRING`. label:new[Introduced in 5.11] -Allowed syntax variations of these types are listed xref::values-and-types/property-structural-constructed.adoc#types-synonyms[here]. +Allowed syntax variations of these types are listed in xref::values-and-types/property-structural-constructed.adoc#types-synonyms[Types and their synonyms]. -[NOTE] -==== There are no supported `OPTIONS` values for property type constraints, but an empty options map is allowed for consistency. -==== -[role=label--enterprise-edition] -[[constraints-syntax-create-node-key]] -=== Node key constraint +For examples on how to create property type constraints, see xref:constraints/managing-constraints.adoc#create-property-type-constraint[Create, show, and drop constraints -> Create property type constraints]. -This command creates a node key constraint on nodes with the specified label and properties. -[source, syntax, role="noheader", indent=0] +[role=label--enterprise-edition] +[[create-key-constraints]] +=== Create key constraints + +.Syntax for creating a node key constraint on a single property +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR (n:LabelName) @@ -227,7 +171,8 @@ REQUIRE n.propertyName IS [NODE] KEY [OPTIONS "{" option: value[, ...] "}"] ---- -[source, syntax, role="noheader", indent=0] +.Syntax for creating a composite node key constraint on multiple properties +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR (n:LabelName) @@ -235,15 +180,8 @@ REQUIRE (n.propertyName_1, ..., n.propertyName_n) IS [NODE] KEY [OPTIONS "{" option: value[, ...] "}"] ---- -Index provider can be specified using the `OPTIONS` clause. - -[role=label--enterprise-edition label--new-5.7] -[[constraints-syntax-create-rel-key]] -=== Relationship key constraint - -This command creates a relationship key constraint on relationships with the specified relationship type and properties. - -[source, syntax, role="noheader", indent=0] +.Syntax for creating a relationship key constraint on a single property label:new[Introduced in 5.7] +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR ()-"["r:RELATIONSHIP_TYPE"]"-() @@ -251,7 +189,8 @@ REQUIRE r.propertyName IS [REL[ATIONSHIP]] KEY [OPTIONS "{" option: value[, ...] "}"] ---- -[source, syntax, role="noheader", indent=0] +.Syntax for creating a composite relationship key constraint on multiple properties label:new[Introduced in 5.7] +[source, syntax] ---- CREATE CONSTRAINT [constraint_name] [IF NOT EXISTS] FOR ()-"["r:RELATIONSHIP_TYPE"]"-() @@ -259,42 +198,26 @@ REQUIRE (r.propertyName_1, ..., r.propertyName_n) IS [REL[ATIONSHIP]] KEY [OPTIONS "{" option: value[, ...] "}"] ---- -Index provider can be specified using the `OPTIONS` clause. - +An index provider can be specified using the `OPTIONS` clause. -[[constraints-syntax-drop]] -== Syntax for dropping constraints +For examples on how to create key constraints, see xref:constraints/managing-constraints.adoc#create-key-constraints[Create, show, and drop constraints -> Create key constraints]. +Key constraints are xref:constraints/managing-constraints.adoc#constraints-and-indexes[index-backed]. -Dropping a constraint is done by specifying the name of the constraint. -[source, syntax, role="noheader", indent=0] ----- -DROP CONSTRAINT constraint_name [IF EXISTS] ----- +[[list-constraints]] +== SHOW CONSTRAINTS -This drop command is optionally idempotent. This means its default behavior is to throw an error if an attempt is made to drop the same constraint twice. -With the `IF EXISTS` flag, no error is thrown and nothing happens should the constraint not exist. -As of Neo4j 5.17, an informational notification is instead returned detailing that the constraint does not exist. +To list all constraints with the default output columns, use `SHOW CONSTRAINTS`. +If all columns are required, use `SHOW CONSTRAINTS YIELD *`. +If only specific columns are required, use `SHOW CONSTRAINTS YIELD field[, ...]`. +The `SHOW CONSTRAINTS` clause can also be filtered using the xref:clauses/where.adoc[`WHERE`] clause. [NOTE] -==== -Dropping a constraint requires the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/database-administration/#access-control-database-administration-constraints[`DROP CONSTRAINT` privilege]. -==== - - -[[constraints-syntax-list]] -== Syntax for listing constraints - -List constraints in the database, either all or filtered on constraint type. - -[NOTE] -==== Listing constraints requires the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/database-administration/#access-control-database-administration-constraints[`SHOW CONSTRAINTS` privilege]. -==== -The simple version of the command allows for a `WHERE` clause and will give back the default set of output columns: -[source, syntax, role="noheader", indent=0] +.Syntax to list constraints with default return columns +[source, syntax] ---- SHOW [ ALL @@ -314,9 +237,8 @@ SHOW [ [WHERE expression] ---- -To get the full set of output columns, a yield clause is needed: - -[source, syntax, role="noheader", indent=0] +.Syntax for listing constraints with full return columns +[source, syntax] ---- SHOW [ ALL @@ -338,7 +260,6 @@ YIELD { * | field[, ...] } [ORDER BY field[, ...]] [SKIP n] [LIMIT n] [RETURN field[, ...] [ORDER BY field[, ...]] [SKIP n] [LIMIT n]] ---- - The type filtering keywords filters the returned constraints on constraint type: [[constraints-syntax-list-type-filter]] @@ -397,54 +318,28 @@ label:new[Introduced in 5.7] |=== +For examples on how to list constraints, see xref:constraints/managing-constraints.adoc#list-constraints[Create, show, and drop constraints -> SHOW CONSTRAINTS]. +For full details of the result columns for the `SHOW CONSTRAINTS` command, see xref:constraints/managing-constraints.adoc#list-constraints-result-columns[Create, show, and drop constraints -> Result columns for listing constraints]. -The returned columns from the show command is: - -.Listing constraints output -[options="header", width="100%", cols="4m,6a,2m"] -|=== -| Column | Description | Type - -| id -| The id of the constraint. label:default-output[] -| INTEGER - -| name -| Name of the constraint (explicitly set by the user or automatically assigned). label:default-output[] -| STRING - -| type -| The ConstraintType of this constraint (`UNIQUENESS` (node uniqueness), `RELATIONSHIP_UNIQUENESS`, `NODE_PROPERTY_EXISTENCE`, `RELATIONSHIP_PROPERTY_EXISTENCE`, `NODE_PROPERTY_TYPE`, `RELATIONSHIP_PROPERTY_TYPE`, `NODE_KEY`, or `RELATIONSHIP_KEY`). label:default-output[] -| STRING +[[drop-constraint]] +== DROP CONSTRAINT -| entityType -| Type of entities this constraint represents (nodes or relationship). label:default-output[] -| STRING - -| labelsOrTypes -| The labels or relationship types of this constraint. label:default-output[] -| LIST - -| properties -| The properties of this constraint. label:default-output[] -| LIST - -| ownedIndex -| The name of the index associated with the constraint or `null`, in case no index is associated with it. label:default-output[] -| STRING +Constraints are dropped using the `DROP` CONSTRAINT command. +Dropping a constraint is done by specifying the name of the constraint. -| propertyType -| The property type the property is restricted to for property type constraints, or `null` for the other constraints. -label:default-output[] label:new[Introduced in 5.9] -| STRING +[NOTE] +Dropping a constraint requires the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/database-administration/#access-control-database-administration-constraints[`DROP CONSTRAINT` privilege]. -| options -| The options passed to `CREATE` command, for the index associated to the constraint, or `null` if no index is associated with the constraint. -| MAP -| createStatement -| Statement used to create the constraint. -| STRING +.Syntax for dropping a constraint by name +[source, syntax] +---- +DROP CONSTRAINT constraint_name [IF EXISTS] +---- -|=== +This command is optionally idempotent. +This means its default behavior is to throw an error if an attempt is made to drop the same constraint twice. +With the `IF EXISTS` flag, no error is thrown and nothing happens should the constraint not exist. +As of Neo4j 5.17, an informational notification is instead returned detailing that the constraint does not exist. +For examples on how to drop constraints, see xref:constraints/managing-constraints.adoc#drop-constraint[Create, show, and drop constraints -> DROP CONSTRAINT]. diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index d5442a8ab..a61b1f14b 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -1178,7 +1178,7 @@ CREATE CONSTRAINT name FOR ()-[r:TYPE]-() REQUIRE r.prop IS :: ---- a| -Extended xref::constraints/examples.adoc#constraints-examples-node-property-type[node] and xref::constraints/examples.adoc#constraints-examples-relationship-property-type[relationship] property type constraints. +Extended xref::constraints/managing-constraints.adoc#create-property-type-constraint-union-type[node and relationship property type constraints]. Closed dynamic union types (`type1 \| type2 \| ...`) are now supported, allowing for types such as: * `INTEGER \| FLOAT` @@ -1260,7 +1260,7 @@ CREATE CONSTRAINT name FOR ()-[r:TYPE]-() REQUIRE r.prop IS :: ---- a| -Extended xref::constraints/examples.adoc#constraints-examples-node-property-type[node] and xref::constraints/examples.adoc#constraints-examples-relationship-property-type[relationship] property type constraints. +Extended xref::constraints/managing-constraints.adoc#type-constraints-allowed-properties[node and relationship property type constraints]. The new supported types are: * `LIST` @@ -1418,7 +1418,7 @@ CREATE CONSTRAINT name FOR ()-[r:TYPE]-() REQUIRE r.prop IS :: ---- a| -Added xref::constraints/examples.adoc#constraints-examples-node-property-type[node] and xref::constraints/examples.adoc#constraints-examples-relationship-property-type[relationship] property type constraints. +Added xref::constraints/managing-constraints.adoc#create-property-type-constraints[node and relationship property type constraints]. The available property types are: * `BOOLEAN` @@ -1568,7 +1568,7 @@ CREATE CONSTRAINT name FOR ()-[r:TYPE]-() REQUIRE r.prop IS RELATIONSHIP KEY ---- a| -Added relationship xref:constraints/syntax.adoc#constraints-syntax-create-rel-key[key] and xref:constraints/syntax.adoc#constraints-syntax-create-rel-unique[uniqueness] constraints. +Added relationship xref:constraints/managing-constraints.adoc#create-key-constraint[key] and xref:constraints/managing-constraints.adoc#create--property-uniqueness-constraint[property uniqueness] constraints. a| label:functionality[] @@ -5030,7 +5030,7 @@ label:new[] DROP CONSTRAINT name ---- a| -xref:constraints/syntax.adoc#constraints-syntax-drop[New command] for dropping a constraint by name, no matter the type. +xref:constraints/managing-constraints.adoc#drop-constraint[New command] for dropping a constraint by name, no matter the type. a| @@ -5142,7 +5142,7 @@ An example of this is `CALL db.index.explicit.searchNodes('my_index','email:me*' | `MATCH (n)-[x:A\|:B\|:C*]-() RETURN n` | Syntax | Deprecated | Replaced by `MATCH (n)-[x:A\|B\|C*]-() RETURN n` | link:/docs/java-reference/5/extending-neo4j/aggregation-functions#extending-neo4j-aggregation-functions[User-defined aggregation functions] | Functionality | Added | | xref:indexes/search-performance-indexes/managing-indexes.adoc[Composite indexes] | Index | Added | -| xref:constraints/examples.adoc#constraints-examples-node-key[Node Key] | Index | Added | Neo4j Enterprise Edition only +| xref:constraints/managing-constraints.adoc#create-key-constraint[Node Key] | Index | Added | Neo4j Enterprise Edition only | `CYPHER runtime=compiled` (Compiled runtime) | Functionality | Added | Neo4j Enterprise Edition only | xref:functions/list.adoc#functions-reverse-list[reverse()] | Function | Extended | Now also allows a list as input | xref:functions/aggregating.adoc#functions-max[max()], xref:functions/aggregating.adoc#functions-min[min()] | Function | Extended | Now also supports aggregation over a set containing both strings and numbers diff --git a/modules/ROOT/pages/indexes/search-performance-indexes/managing-indexes.adoc b/modules/ROOT/pages/indexes/search-performance-indexes/managing-indexes.adoc index 9af1388a6..2487e32ad 100644 --- a/modules/ROOT/pages/indexes/search-performance-indexes/managing-indexes.adoc +++ b/modules/ROOT/pages/indexes/search-performance-indexes/managing-indexes.adoc @@ -235,7 +235,7 @@ However, other predicates are only used when it is known that the property is co * `n.prop = "string"` * `n.prop IN ["a", "b", "c"]` -This means that a text index is not able to solve, for example, e.g. `a.prop = b.prop`, unless a xref:constraints/examples.adoc#constraints-examples-node-property-type[type constraint] also exists on the property. +This means that a text index is not able to solve, for example, e.g. `a.prop = b.prop`, unless a xref:constraints/managing-constraints.adoc#create-property-type-constraints[property type constraint] also exists on the property. Text indexes support the following predicates: @@ -280,8 +280,8 @@ CONTAINS |=== -As of Neo4j 5.11, the above set of predicates can be extended with the use of type constraints. -See the section about xref:indexes/search-performance-indexes/using-indexes.adoc#type-constraints[index compatibility and type constraints] for more information. +As of Neo4j 5.11, the above set of predicates can be extended with the use of property type constraints. +See the section about xref:indexes/search-performance-indexes/using-indexes.adoc#type-constraints[index compatibility and property type constraints] for more information. [TIP] Text indexes are only used for exact query matches. To perform approximate matches (including, for example, variations and typos), and to compute a similarity score between `STRING` values, use semantic xref:indexes/semantic-indexes/full-text-indexes.adoc[full-text indexes] instead. @@ -426,8 +426,8 @@ point.distance(n.prop, center) < = distance |=== -As of Neo4j 5.11, the above set of predicates can be extended with the use of type constraints. -See xref:indexes/search-performance-indexes/using-indexes.adoc#index-compatibility-type-constraints[Index compatibility and type constraints] for more information. +As of Neo4j 5.11, the above set of predicates can be extended with the use of property type constraints. +See xref:indexes/search-performance-indexes/using-indexes.adoc#index-compatibility-type-constraints[Index compatibility and property type constraints] for more information. [TIP] To learn more about the spatial data types supported by Cypher, see the page about xref:values-and-types/spatial.adoc[Spatial values]. @@ -1109,7 +1109,7 @@ Unable to drop index: Index belongs to constraint: `uniqueBookIsbn` ---- Dropping the index-backed constraint will also remove the backing index. -For more information, see xref:constraints/examples.adoc#constraints-examples-drop-constraint[Drop a constraint by name]. +For more information, see xref:constraints/managing-constraints.adoc#drop-constraint[Drop a constraint by name]. [discrete] [[drop-a-non-existing-index]] diff --git a/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc b/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc index bcf88382b..7a163a8f1 100644 --- a/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc +++ b/modules/ROOT/pages/indexes/search-performance-indexes/using-indexes.adoc @@ -892,15 +892,15 @@ The xref:functions/string.adoc#functions-tostring[`toString`] function can also [role=label--new-5.11] [[type-constraints]] -=== Type constraints +=== Property type constraints For indexes that are compatible only with specific types (i.e. text and point indexes), the Cypher planner needs to deduce that a predicate will evaluate to `null` for non-compatible values in order to use the index. If a predicate is not explicitly defined as the required type (`STRING` or `POINT`), this can lead to situations where a text or point index is not used. -Since xref:constraints/examples.adoc#constraints-examples-node-property-type[type constraints] guarantee that a property is always of the same type, they can be used to extend the scenarios in which text and point indexes are compatible with a predicate. +Since xref:constraints/managing-constraints.adoc#create-property-type-constraints[property type constraints] guarantee that a property is always of the same type, they can be used to extend the scenarios in which text and point indexes are compatible with a predicate. -To show this, the following example will first drop the existing range index on the `name` property (this is necessary because type constraints only extend the compatibility of type-specific indexes - range indexes are not limited by a value type). -It will then run the same query with a `WHERE` predicate on the `name` property (for which there exists a previously created text index) before and after creating a type constraint, and compare the resulting execution plans. +To show this, the following example will first drop the existing range index on the `name` property (this is necessary because property type constraints only extend the compatibility of type-specific indexes - range indexes are not limited by a value type). +It will then run the same query with a `WHERE` predicate on the `name` property (for which there exists a previously created text index) before and after creating a property type constraint, and compare the resulting execution plans. .Drop range index [source,cypher] @@ -938,7 +938,7 @@ Total database accesses: 562, total allocated memory: 472 This plan shows that the available text index on the `name` property was not used to solve the predicate. This is because the planner was not able to deduce that all `name` values are of type `STRING`. -However, if a type constraint is created to ensure that all `name` properties have a `STRING` value, a different query plan is generated. +However, if a property type constraint is created to ensure that all `name` properties have a `STRING` value, a different query plan is generated. .Create `STRING` type constraint on the `name` property [source,cypher] @@ -947,7 +947,7 @@ CREATE CONSTRAINT type_constraint FOR (n:PointOfInterest) REQUIRE n.name IS :: STRING ---- -.Rerun the query after the creation of a type constraint +.Rerun the query after the creation of a property type constraint [source,cypher] ---- PROFILE @@ -972,11 +972,11 @@ RETURN count(n) AS nodes Total database accesses: 186, total allocated memory: 472 ---- -Because of the type constraint on the `name` property, the planner is now able to deduce that all `name` properties are of type `STRING`, and therefore use the available text index. +Because of the property type constraint on the `name` property, the planner is now able to deduce that all `name` properties are of type `STRING`, and therefore use the available text index. -Point indexes can be extended in the same way if a type constraint is created to ensure that all properties are `POINT` values. +Point indexes can be extended in the same way if a property type constraint is created to ensure that all properties are `POINT` values. -Note that xref:constraints/examples.adoc#constraints-examples-node-property-existence[property existence constraints] do not currently leverage index use in the same way. +Note that xref:constraints/managing-constraints.adoc#create-property-existence-constraints[property existence constraints] do not currently leverage index use in the same way. [[Heuristics]] == Heuristics: deciding what to index diff --git a/modules/ROOT/pages/introduction/cypher-neo4j.adoc b/modules/ROOT/pages/introduction/cypher-neo4j.adoc index 11c70a69e..5d3482c59 100644 --- a/modules/ROOT/pages/introduction/cypher-neo4j.adoc +++ b/modules/ROOT/pages/introduction/cypher-neo4j.adoc @@ -32,16 +32,12 @@ All users have full access rights. | Constraints a| All constraints: -xref::constraints/examples.adoc#constraints-examples-node-property-existence[node property existence constraints], -xref::constraints/examples.adoc#constraints-examples-relationship-property-existence[relationship property existence constraints], -xref::constraints/examples.adoc#constraints-examples-node-property-type[node property type constraints], -xref::constraints/examples.adoc#constraints-examples-relationship-property-type[relationship property type constraints], -xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node property uniqueness constraints], -xref::constraints/examples.adoc#constraints-examples-relationship-uniqueness[relationship property uniqueness constraints], -xref::constraints/examples.adoc#constraints-examples-node-key[node key constraints], and -xref::constraints/examples.adoc#constraints-examples-relationship-key[relationship key constraints]. +xref::constraints/managing-constraints.adoc#create-property-existence-constraints[node and relationship property existence constraints], +xref::constraints/managing-constraints.adoc#create-property-type-constraints[node and relationship property type constraints], +xref::constraints/managing-constraints.adoc#create-property-uniqueness-constraints[node and relationship property uniqueness constraints], +xref::constraints/managing-constraints.adoc#create-key-constraints[node and relationship key constraints]. a| -Only xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node] and xref::constraints/examples.adoc#constraints-examples-relationship-uniqueness[relationship] property uniqueness constraints. +Only xref::constraints/managing-constraints.adoc#create-property-uniqueness-constraints[node and relationship property uniqueness constraints]. |=== diff --git a/modules/ROOT/pages/introduction/cypher-overview.adoc b/modules/ROOT/pages/introduction/cypher-overview.adoc index a8d7ea846..ebaac533c 100644 --- a/modules/ROOT/pages/introduction/cypher-overview.adoc +++ b/modules/ROOT/pages/introduction/cypher-overview.adoc @@ -36,7 +36,7 @@ However, there are some important differences between the two: *Cypher is schema-flexible*:: While it is both possible and advised to enforce partial schemas using xref:constraints/index.adoc[indexes and constraints], Cypher and Neo4j offers a greater degree of schema-flexibility than SQL and a relational database. -More specifically, nodes and relationships in a Neo4j database do not have to have a specific property set to them because other nodes or relationships in the same graph have that property (unless there is an xref:constraints/examples.adoc#constraints-examples-node-property-existence[existence constraint created on that specific property]). +More specifically, nodes and relationships in a Neo4j database do not have to have a specific property set to them because other nodes or relationships in the same graph have that property (unless there is an xref:constraints/managing-constraints.adoc#create-property-existence-constraints[property existence constraint] created on that specific property). This means that users are not required to use a fixed schema to represent data and that they can add new attributes and relationships as their graphs evolve. *Query order*:: diff --git a/modules/ROOT/pages/patterns/shortest-paths.adoc b/modules/ROOT/pages/patterns/shortest-paths.adoc index 01e61f3ba..b6f540e91 100644 --- a/modules/ROOT/pages/patterns/shortest-paths.adoc +++ b/modules/ROOT/pages/patterns/shortest-paths.adoc @@ -595,4 +595,4 @@ RETURN p [TIP] Sometimes the planner cannot make reliable estimations about how many nodes a pattern node will match. -Consider using a xref:constraints/index.adoc#unique-node-property[uniqueness constraint] where applicable to help the planner get more reliable estimates. +Consider using a xref:constraints/managing-constraints.adoc#create-property-uniqueness-constraints[property uniqueness constraint] where applicable to help the planner get more reliable estimates. diff --git a/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc b/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc index 618ade925..a08608f9e 100644 --- a/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc +++ b/modules/ROOT/pages/values-and-types/property-structural-constructed.adoc @@ -74,7 +74,7 @@ For more details, see xref::values-and-types/working-with-null.adoc[working with The table below shows the types and their syntactic synonyms. -These types (and their synonyms) can be used in xref::values-and-types/type-predicate.adoc[type predicate expressions] and in xref::constraints/examples.adoc#constraints-examples-node-property-type[node] and xref::constraints/examples.adoc#constraints-examples-relationship-property-type[relationship] property type constraints. +These types (and their synonyms) can be used in xref::values-and-types/type-predicate.adoc[type predicate expressions] and in xref::constraints/managing-constraints.adoc#create-property-type-constraints[property type constraints]. They are also returned as a `STRING` value when using the xref::functions/scalar.adoc#functions-valueType[valueType()] function. However, not all types can be used in all places. @@ -121,7 +121,7 @@ The type `PROPERTY VALUE` is expanded to a closed dynamic union of all valid pro For example, given the closed dynamic type `BOOL | LIST | BOOLEAN | LIST`, the normalized type would be: `BOOLEAN | LIST`. -This normalization is run on types used in xref::values-and-types/type-predicate.adoc[type predicate expressions], and in xref::constraints/examples.adoc#constraints-examples-node-property-type[node] and xref::constraints/examples.adoc#constraints-examples-relationship-property-type[relationship] property type constraints. +This normalization is run on types used in xref::values-and-types/type-predicate.adoc[type predicate expressions], and in xref::constraints/managing-constraints.adoc#create-property-type-constraints[property type constraints]. Type normalization is also used to ensure the consistency of the output for the xref::functions/scalar.adoc#functions-valueType[valueType()] function. [[ordering-of-types]] From 1073249259c283ec4bb4ba8b060cbf6e0fa7eab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:00:22 +0200 Subject: [PATCH 51/64] Add new label to type constraints and page alias (#1066) --- modules/ROOT/pages/constraints/index.adoc | 2 +- modules/ROOT/pages/constraints/managing-constraints.adoc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/constraints/index.adoc b/modules/ROOT/pages/constraints/index.adoc index f906e317b..7e5341bba 100644 --- a/modules/ROOT/pages/constraints/index.adoc +++ b/modules/ROOT/pages/constraints/index.adoc @@ -7,7 +7,7 @@ The following constraints are available in Neo4j: * *Property uniqueness constraints* ensure that the combined property values are unique for all nodes with a specific label or all relationships with a specific type. * *Property existence constraints* ensure that a property exists either for all nodes with a specific label or for all relationships with a specific type. label:enterprise-edition[] -* *Property type constraints* ensure that a property has the required property type for all nodes with a specific label or for all relationships with a specific type. label:enterprise-edition[] +* *Property type constraints* ensure that a property has the required property type for all nodes with a specific label or for all relationships with a specific type. label:new[Introduced in 5.9] label:enterprise-edition[] * *Key constraints* ensure that all properties exist and that the combined property values are unique for all nodes with a specific label or all relationships with a specific type.label:enterprise-edition[] To learn more about creating, listing, and dropping these constraints, as well as information about index-backed constraints, constraint creation failures and data violation scenarios, and more, see xref:constraints/managing-constraints.adoc[]. diff --git a/modules/ROOT/pages/constraints/managing-constraints.adoc b/modules/ROOT/pages/constraints/managing-constraints.adoc index bcd24e97b..98c48b091 100644 --- a/modules/ROOT/pages/constraints/managing-constraints.adoc +++ b/modules/ROOT/pages/constraints/managing-constraints.adoc @@ -1,4 +1,5 @@ :description: Information about creating, listing, and dropping Neo4j's constraints. +:page-aliases: constraints/examples.adoc include::https://raw.githubusercontent.com/neo4j-graphacademy/courses/main/asciidoc/courses/cypher-indexes-constraints/ad.adoc[] = Create, show, and drop constraints @@ -7,7 +8,7 @@ The following constraint types are available in Neo4j: * xref:constraints/managing-constraints.adoc#create-property-uniqueness-constraints[Property uniqueness constraints] * xref:constraints/managing-constraints.adoc#create-property-existence-constraints[Property existence constraints] label:enterprise-edition[] -* xref:constraints/managing-constraints.adoc#create-property-type-constraints[Property type constraints] label:enterprise-edition[] +* xref:constraints/managing-constraints.adoc#create-property-type-constraints[Property type constraints] label:new[Introduced in 5.9] label:enterprise-edition[] * xref:constraints/managing-constraints.adoc#create-key-constraints[Key constraints] label:enterprise-edition[] From 1085290d1b21af5672afc67f86e7b96f9c18c99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Mon, 21 Oct 2024 09:17:36 +0200 Subject: [PATCH 52/64] Fix typo and change auradb enterprise to auradb virtual dedicated cloud on parallel runtime page (#1068) --- .../ROOT/pages/planning-and-tuning/runtimes/reference.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/planning-and-tuning/runtimes/reference.adoc b/modules/ROOT/pages/planning-and-tuning/runtimes/reference.adoc index 57e009abc..24d12435b 100644 --- a/modules/ROOT/pages/planning-and-tuning/runtimes/reference.adoc +++ b/modules/ROOT/pages/planning-and-tuning/runtimes/reference.adoc @@ -79,8 +79,8 @@ For more information about configuration settings in Neo4j, see the link:{neo4j- == Aura The parallel runtime can only be run on Aura instances with 3 or more CPUs. -This means that the parallel runtime is not available to users to users of AuraDB Free. -Nor is it available on instances of AuraDB Professional and AuraDB Enterprise with 2 or fewer CPUs. +This means that the parallel runtime is not available to users of AuraDB Free. +Nor is it available on instances of AuraDB Professional, AuraDB Business Critical, and AuraDB Virtual Dedicated Cloud with 2 or fewer CPUs. Attempting to run a query with the parallel runtime on instances with 2 or fewer CPUs will generate the following error message: @@ -92,7 +92,7 @@ Parallel runtime has been disabled, please enable it or upgrade to a bigger Aura [TIP] ==== -Users of AuraDB Professional and AuraDB Enterprise select the number of available CPUs when creating an instance. +Users of AuraDB Professional, AuraDB Business Critical, and AuraDB Virtual Dedicated Cloud select the number of available CPUs when creating an instance. More information about the various tiers of AuraDB can be found on the link:https://neo4j.com/pricing/[Neo4j Pricing page]. ==== From 1a55a02ccfe50598a72139afeb11d455c7e81e49 Mon Sep 17 00:00:00 2001 From: Richard Sill <156673635+rsill-neo4j@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:17:16 +0200 Subject: [PATCH 53/64] Intro with a link to ops manual for cloud URI section (#1071) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jens Pryce-Åklundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- modules/ROOT/pages/clauses/load-csv.adoc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/ROOT/pages/clauses/load-csv.adoc b/modules/ROOT/pages/clauses/load-csv.adoc index fa5804f1b..24050d9bb 100644 --- a/modules/ROOT/pages/clauses/load-csv.adoc +++ b/modules/ROOT/pages/clauses/load-csv.adoc @@ -171,6 +171,14 @@ Added 4 nodes, Set 8 properties, Added 4 labels [role=label--enterprise-edition label--not-on-aura] === Import from cloud URIs +You can import data from a number of different cloud storages: + +* xref:clauses/load-csv.adoc#azure-cloud-storage[Azure Cloud Storage] +* xref:clauses/load-csv.adoc#google-cloud-storage[Google Cloud Storage] +* ref:clauses/load-csv.adoc#aws-s3[AWS S3] + +See link:{neo4j-docs-base-uri}/operations-manual/current/backup-restore/restore-dump/#load-dump-cloud-storage[Operations Manual -> Load a dump from a cloud storage] on how to set up access to cloud storages. + [[azure-cloud-storage]] [role=label--new-5.24] ==== Import from an Azure Cloud Storage URI From 6d4287c79cb5d46928e89a5b308e3e31fc2dacdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Mon, 21 Oct 2024 13:39:24 +0200 Subject: [PATCH 54/64] Make Cypher Manual AuraDB Business Critical aware (#1072) Co-authored-by: Jessica Wright <49636617+AlexicaWright@users.noreply.github.com> --- .../ROOT/pages/introduction/cypher-aura.adoc | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/modules/ROOT/pages/introduction/cypher-aura.adoc b/modules/ROOT/pages/introduction/cypher-aura.adoc index c1cd41633..bd117c999 100644 --- a/modules/ROOT/pages/introduction/cypher-aura.adoc +++ b/modules/ROOT/pages/introduction/cypher-aura.adoc @@ -2,7 +2,7 @@ = Cypher and Aura :description: This section provides an introduction to the Cypher query language. -This section gives a brief overview of Aura, and how Cypher differs to users of Aura. +This page provides a brief overview of Neo4j Aura and its relationship to Cypher. == What is Aura? @@ -13,36 +13,30 @@ AuraDB is a graph database service for developers building intelligent applicati AuraDB is available on the following tiers: * AuraDB Free -* AuraDB Pro -* AuraDB Enterprise +* AuraDB Professional +* AuraDB Business Critical +* AuraDB Virtual Dedicated Cloud For more information, see link:{neo4j-docs-base-uri}/aura/auradb[Aura docs - Neo4j AuraDB overview]. AuraDS is available on the following tiers: -* AuraDS Pro +* Graph Data Science Community +* Graph Data Science Enterprise +* AuraDS Professional * AuraDS Enterprise For more information, see link:{neo4j-docs-base-uri}/aura/aurads[Aura docs - Neo4j AuraDS overview]. == Using Cypher on Aura -Most Cypher features are available on all tiers of Aura. -There are, however, some features which are not available to Aura instances. +Most Cypher features are available across all tiers of Aura. +However, certain features are not supported in Aura instances. For example, it is not possible to create, alter, or drop databases using Aura, nor is it possible to alter or drop servers. -There are also certain Cypher features which are only available on AuraDB Enterprise instances. -These can be categorized as the role-based access-control features of Cypher. -For example, it is not possible to create, alter, or drop roles using AuraDB Free, AuraDB Pro, AuraDS Pro, or AuraDS Enterprise, but it is possible using AuraDB Enterprise. - -The Cypher Manual uses two different labels to differentiate this distinction: - -[options="header,cols=""2a,2a"] -|=== -| Label | Description -| label:not-on-aura[Not Available on Aura] | Cypher feature not available on any tier of Aura. -| label:aura-db-enterprise[AuraDB Enterprise] | Cypher feature only available on AuraDB Enterprise. -|=== +Additionally, some Cypher features are exclusive to AuraDB Business Critical and AuraDB Virtual Dedicated Cloud tiers. +These primarily fall under database administration and role-based access control capabilities. +For more information, see the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/[Operations Manual -> Database administration] and the link:{neo4j-docs-base-uri}/operations-manual/{page-version}/authentication-authorization/[Operations Manual -> Authentication and authorization]. == Aura and the Cypher Cheat Sheet @@ -50,4 +44,4 @@ Each different tier of Aura has a customized version of the Cypher Cheat Sheet w The Cypher Cheat Sheet can be accessed link:{neo4j-docs-base-uri}/cypher-cheat-sheet/{page-version}/auradb-enterprise/[here]. You can select your desired Aura tier and Neo4j version by using the dropdown menus provided. -Note that the default tier is AuraDB Enterprise. +Note that the default tier is AuraDB Virtual Dedicated Cloud. From 1a428e02e518920eec94750c9411ade39226185f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 22 Oct 2024 11:02:05 +0200 Subject: [PATCH 55/64] Fix remaining examples of CALL subqueries without variable scope clause (#1074) --- modules/ROOT/pages/clauses/union.adoc | 7 ++++++- modules/ROOT/pages/clauses/use.adoc | 5 +++-- modules/ROOT/pages/functions/graph.adoc | 14 ++++++++++++-- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/clauses/union.adoc b/modules/ROOT/pages/clauses/union.adoc index 85b261d97..2df4687aa 100644 --- a/modules/ROOT/pages/clauses/union.adoc +++ b/modules/ROOT/pages/clauses/union.adoc @@ -131,10 +131,15 @@ The combined result is returned, without duplicates. The `UNION` clause can be used within a xref:subqueries/call-subquery.adoc[`CALL` subquery] to further process the combined results before a final output is returned. For example, the below query xref:functions/aggregating.adoc#functions-count[counts] the occurrences of each `name` property returned after the `UNION ALL` within the `CALL` subquery. +[NOTE] +The below query uses an empty xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause]: `CALL () { ... }` (introduced in Neo4j 5.23). +If you are using an older version of Neo4j, use `CALL { ... }` instead. +For more information, see xref:subqueries/call-subquery.adoc#import-variables[CALL subqueries -> Importing variables]. + .Query [source, cypher] ---- -CALL { +CALL () { MATCH (a:Actor) RETURN a.name AS name UNION ALL diff --git a/modules/ROOT/pages/clauses/use.adoc b/modules/ROOT/pages/clauses/use.adoc index 20df616ca..29c744c72 100644 --- a/modules/ROOT/pages/clauses/use.adoc +++ b/modules/ROOT/pages/clauses/use.adoc @@ -41,13 +41,14 @@ USE + [source, syntax, role="noheader"] ---- -CALL { +CALL () { USE } ---- + -In subqueries, a `USE` clause may appear as the second clause, if directly following an xref::subqueries/call-subquery.adoc#call-importing-variables[importing `WITH` clause]. +In subqueries, a `USE` clause may appear directly following the xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause]: `CALL () { ... }` (introduced in Neo4j 5.23). +Or, if you are using an older version of Neo4j, directly following an xref::subqueries/call-subquery.adoc#importing-with[importing `WITH` clause]. When executing queries against a composite database, the `USE` clause must only refer to graphs that are part of the current composite database. diff --git a/modules/ROOT/pages/functions/graph.adoc b/modules/ROOT/pages/functions/graph.adoc index 8ac1fcd0e..9404b48f5 100644 --- a/modules/ROOT/pages/functions/graph.adoc +++ b/modules/ROOT/pages/functions/graph.adoc @@ -117,7 +117,7 @@ Properties for all graphs on the current composite database are returned. UNWIND graph.names() AS name WITH name, graph.propertiesByName(name) AS props WHERE "A" IN props.tags -CALL { +CALL () { USE graph.byName(name) MATCH (n) RETURN n @@ -127,6 +127,11 @@ RETURN n Returns all nodes from a subset of graphs that have a `tags` property containing `"A"`. +[NOTE] +The above query uses an empty xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause]: `CALL () { ... }` (introduced in Neo4j 5.23). +If you are using an older version of Neo4j, use `CALL { ... }` instead. +For more information, see xref:subqueries/call-subquery.adoc#import-variables[CALL subqueries -> Importing variables]. + ====== [[functions-graph-byname]] @@ -148,7 +153,7 @@ Returns all nodes from a subset of graphs that have a `tags` property containing [source, cypher, indent=0] ---- UNWIND graph.names() AS graphName -CALL { +CALL () { USE graph.byName(graphName) MATCH (n) RETURN n @@ -158,6 +163,11 @@ RETURN n Returns all nodes from all graphs on the current composite database. +[NOTE] +The above query uses an empty xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause]: `CALL () { ... }` (introduced in Neo4j 5.23). +If you are using an older version of Neo4j, use `CALL { ... }` instead. +For more information, see xref:subqueries/call-subquery.adoc#import-variables[CALL subqueries -> Importing variables]. + ====== [role=label--new-5.13] From 5f6f6ee3c0634807e5b784866c7389a834f76203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 22 Oct 2024 11:28:14 +0200 Subject: [PATCH 56/64] Fix SHOW CONSTRAINTS table (#1075) --- modules/ROOT/pages/constraints/managing-constraints.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/ROOT/pages/constraints/managing-constraints.adoc b/modules/ROOT/pages/constraints/managing-constraints.adoc index 98c48b091..148258f0f 100644 --- a/modules/ROOT/pages/constraints/managing-constraints.adoc +++ b/modules/ROOT/pages/constraints/managing-constraints.adoc @@ -1543,6 +1543,8 @@ SHOW CONSTRAINTS YIELD * [source, queryresult] ---- +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| id | name | type | entityType | labelsOrTypes | properties | ownedIndex | propertyType | options | createStatement | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | 21 | "actor_fullname" | "NODE_KEY" | "NODE" | ["Actor"] | ["firstname", "surname"] | "actor_fullname" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `actor_fullname` FOR (n:`Actor`) REQUIRE (n.`firstname`, n.`surname`) IS NODE KEY" | | 10 | "author_name" | "NODE_PROPERTY_EXISTENCE" | "NODE" | ["Author"] | ["name"] | NULL | NULL | NULL | "CREATE CONSTRAINT `author_name` FOR (n:`Author`) REQUIRE (n.`name`) IS NOT NULL" | | 3 | "book_isbn" | "UNIQUENESS" | "NODE" | ["Book"] | ["isbn"] | "book_isbn" | NULL | {indexConfig: {}, indexProvider: "range-1.0"} | "CREATE CONSTRAINT `book_isbn` FOR (n:`Book`) REQUIRE (n.`isbn`) IS UNIQUE" | From 720b73285dfbdf8bee17a9e0d3621653a3e1f997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:01:13 +0200 Subject: [PATCH 57/64] Aura update for parallel runtime (#1076) --- .../pages/planning-and-tuning/runtimes/reference.adoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/planning-and-tuning/runtimes/reference.adoc b/modules/ROOT/pages/planning-and-tuning/runtimes/reference.adoc index 24d12435b..015a83712 100644 --- a/modules/ROOT/pages/planning-and-tuning/runtimes/reference.adoc +++ b/modules/ROOT/pages/planning-and-tuning/runtimes/reference.adoc @@ -78,11 +78,11 @@ For more information about configuration settings in Neo4j, see the link:{neo4j- [[aura]] == Aura -The parallel runtime can only be run on Aura instances with 3 or more CPUs. -This means that the parallel runtime is not available to users of AuraDB Free. -Nor is it available on instances of AuraDB Professional, AuraDB Business Critical, and AuraDB Virtual Dedicated Cloud with 2 or fewer CPUs. +The parallel runtime is available on all non-free AuraDB instances, regardless of their size or CPU count. +Additionally, when a query is run with parallel runtime on an Aura instance, it can utilize up to the total number of available CPUs. -Attempting to run a query with the parallel runtime on instances with 2 or fewer CPUs will generate the following error message: +The parallel runtime is disabled on AuraDB Free instances. +Attempting to run a query with parallel runtime on AuraDB Free will throw the following error message: .Error message [source,error] @@ -92,7 +92,7 @@ Parallel runtime has been disabled, please enable it or upgrade to a bigger Aura [TIP] ==== -Users of AuraDB Professional, AuraDB Business Critical, and AuraDB Virtual Dedicated Cloud select the number of available CPUs when creating an instance. +Users of AuraDB Professional, AuraDB Business Critical, and AuraDB Virtual Dedicated Cloud select the the size and the number of available CPUs when creating an instance. More information about the various tiers of AuraDB can be found on the link:https://neo4j.com/pricing/[Neo4j Pricing page]. ==== From 1aae0d50634c4417b440c69398456f741dead341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:01:12 +0200 Subject: [PATCH 58/64] Document max identifier length (#1077) --- .../pages/appendix/gql-conformance/index.adoc | 4 ++-- .../gql-conformance/supported-optional.adoc | 5 ++++ ...ions-additions-removals-compatibility.adoc | 23 +++++++++++++++++-- modules/ROOT/pages/syntax/naming.adoc | 8 +++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/modules/ROOT/pages/appendix/gql-conformance/index.adoc b/modules/ROOT/pages/appendix/gql-conformance/index.adoc index 2aafc9772..438f89042 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/index.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/index.adoc @@ -1,8 +1,8 @@ :description: Overview of Cypher's conformance to GQL. = GQL conformance -*Last updated*: 13 September 2024 + -*Neo4j version*: 5.24 +*Last updated*: 24 October 2024 + +*Neo4j version*: 5.25 GQL is the new link:https://www.iso.org/home.html[ISO] International Standard query language for graph databases. diff --git a/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc b/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc index b71364b84..77defa1ec 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/supported-optional.adoc @@ -93,6 +93,11 @@ These codes order the features in the table below. | xref:patterns/reference.adoc#graph-patterns-rules-variable-references[Graph patterns -> Rules] | +| GB01 +| Long identifiers +| xref:syntax/naming.adoc#identifier-length-limit[Naming rules and recommendations -> Identifier length limit] +| + | GF01 | Enhanced numeric functions | xref:functions/mathematical-numeric.adoc#functions-abs[`abs()`], xref:functions/mathematical-numeric.adoc#functions-floor[`floor()`], xref:functions/mathematical-logarithmic.adoc#functions-sqrt[`sqrt()`]. diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index a61b1f14b..aed06bb68 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -36,6 +36,27 @@ CREATE DATABASE db OPTIONS { existingDataSeedInstance: ... } | The `CREATE DATABASE` option `existingDataSeedInstance` has been deprecated and replaced with the option link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/standard-databases/create-database/#manage-databases-create-database-options[`existingDataSeedServer`]. The functionality is unchanged. |=== +=== Updated features + +[cols="2", options="header"] +|=== +| Feature +| Details + +a| +label:functionality[] +label:updated[] +[source, cypher, role="noheader"] +---- +CREATE (n:Label {property: 'name'}, +()-[r:REL_TYPE]->() +---- +| Neo4j's link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-internals/store-formats/#store-format-overview[block format] now implements xref:appendix/gql-conformance/index.adoc[GQL's] limit on the maximum length of identifiers. + +The maximum limit is set to 16,383 characters in an identifier. +This means that node labels, relationship types, and property keys cannot include more than 16,383 characters. +|=== + === New features [cols="2", options="header"] @@ -53,8 +74,6 @@ CREATE DATABASE db OPTIONS { existingDataSeedServer: ... } | The option link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-administration/standard-databases/create-database/#manage-databases-create-database-options[`existingDataSeedServer`] has been added to `CREATE DATABASE`. The functionality is the same as the deprecated option `existingDataSeedServer`, which this replaces. |=== - - [[cypher-deprecations-additions-removals-5.24]] == Neo4j 5.24 diff --git a/modules/ROOT/pages/syntax/naming.adoc b/modules/ROOT/pages/syntax/naming.adoc index 91c927682..d4b9357c1 100644 --- a/modules/ROOT/pages/syntax/naming.adoc +++ b/modules/ROOT/pages/syntax/naming.adoc @@ -71,3 +71,11 @@ Here are the recommended naming conventions: | Relationship types | Upper-case, using underscore to separate words | `:OWNS_VEHICLE` rather than `:ownsVehicle` etc. |=== +[role=label--new-5.25] +[[identifier-length-limit]] +== Length limit of identifiers + +Neo4j's link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-internals/store-formats/#store-format-overview[block format] implements xref:appendix/gql-conformance/index.adoc[GQL's] limit on the maximum length of identifiers. + +The maximum limit is set to 16,383 characters in an identifier. +This means that node labels, relationship types, and property keys cannot include more than 16,383 characters. From ad1e5fd921a8b311634f7bb14ba4d67f8cb6c1df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:25:51 +0200 Subject: [PATCH 59/64] Add missing curly bracket (#1079) --- .../pages/deprecations-additions-removals-compatibility.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index aed06bb68..db0c05224 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -48,7 +48,7 @@ label:functionality[] label:updated[] [source, cypher, role="noheader"] ---- -CREATE (n:Label {property: 'name'}, +CREATE (n:Label {property: 'name'}), ()-[r:REL_TYPE]->() ---- | Neo4j's link:{neo4j-docs-base-uri}/operations-manual/{page-version}/database-internals/store-formats/#store-format-overview[block format] now implements xref:appendix/gql-conformance/index.adoc[GQL's] limit on the maximum length of identifiers. From ea86dc950b7971b4107d726868a5f1e8e7a7463d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:22:45 +0200 Subject: [PATCH 60/64] Update MATCH page (#1080) --- modules/ROOT/images/graph_match_clause.svg | 2 +- modules/ROOT/pages/clauses/match.adoc | 515 ++++++++++++--------- 2 files changed, 299 insertions(+), 218 deletions(-) diff --git a/modules/ROOT/images/graph_match_clause.svg b/modules/ROOT/images/graph_match_clause.svg index 9426d8918..d2481798f 100644 --- a/modules/ROOT/images/graph_match_clause.svg +++ b/modules/ROOT/images/graph_match_clause.svg @@ -1 +1 @@ -DIRECTEDACTED_INrole:'Gordon Gekko'ACTED_INrole:'Carl Fox'ACTED_INrole:'President Andrew Shepherd'ACTED_INrole:'A.J. MacInerney'ACTED_INrole:'Bud Fox'DIRECTEDFATHER_OFPersonname:'Oliver Stone'Movietitle:'Wall Street'Personname:'Michael Douglas'Personname:'Martin Sheen'Movietitle:'The American President'Personname:'Charlie Sheen'Personname:'Rob Reiner' \ No newline at end of file +DIRECTEDACTED_INrole:'Gordon Gekko'ACTED_INrole:'Carl Fox'ACTED_INrole:'President Andrew Shepherd'ACTED_INrole:'A.J. MacInerney'ACTED_INrole:'Bud Fox'DIRECTEDPersonname:'Oliver Stone'Movietitle:'Wall Street'Personname:'Michael Douglas'Personname:'Martin Sheen'Movietitle:'The American President'Personname:'Charlie Sheen'Personname:'Rob Reiner' diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index a26f46c2b..f04bf857d 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -1,80 +1,56 @@ :description: The `MATCH` clause is used to search for the pattern described in it. include::https://raw.githubusercontent.com/neo4j-graphacademy/courses/main/asciidoc/ads/data-analysis.adoc[] -[[query-match]] = MATCH -[[match-introduction]] -== Introduction - -The `MATCH` clause allows you to specify the patterns Neo4j will search for in the database. -This is the primary way of getting data into the current set of bindings. -For more information about how `MATCH` is used to find patterns (including xref:patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path patterns], xref:patterns/variable-length-patterns.adoc#quantified-relationships[quantified relationships], and xref:patterns/shortest-paths.adoc[shortest paths]), see the section on xref::patterns/index.adoc[Patterns]. - -`MATCH` is often coupled to a `WHERE` part which adds restrictions, or predicates, to the `MATCH` patterns, making them more specific. -The predicates are part of the pattern description, and should not be considered a filter applied only after the matching is done. -_This means that `WHERE` should always be put together with the `MATCH` clause it belongs to._ - -`MATCH` can occur at the beginning of the query or later, possibly after a `WITH`. -If it is the first clause, nothing will have been bound yet, and Neo4j will design a search to find the results matching the clause and any associated predicates specified in any `WHERE` part. -This could involve a scan of the database, a search for nodes having a certain label, or a search of an index to find starting points for the pattern matching. -Nodes and relationships found by this search are available as _bound pattern elements,_ and can be used for pattern matching of paths. -They can also be used in any further `MATCH` clauses, where Neo4j will use the known elements, and from there find further unknown elements. - -Cypher is declarative, and so usually the query itself does not specify the algorithm to use to perform the search. -Neo4j will automatically work out the best approach to finding start nodes and matching patterns. -Predicates in `WHERE` parts can be evaluated before pattern matching, during pattern matching, or after finding matches. -However, there are cases where you can influence the decisions taken by the query compiler. -Read more about indexes in xref:indexes/search-performance-indexes/managing-indexes.adoc[], and more about specifying hints to force Neo4j to solve a query in a specific way in xref::indexes/search-performance-indexes/index-hints.adoc[Planner hints and the USING keyword]. - +The `MATCH` clause enables you to define specific patterns that the database will search for within its graph structure. +The `MATCH` clause can specify the nodes, relationships, and properties in a pattern, allowing for queries that traverse the graph to retrieve relevant data. [[match-example-graph]] == Example graph The following graph is used for the examples below: -image::graph_match_clause.svg[width="600",role="middle"] +image::graph_match_clause.svg[width="500",role="middle"] To recreate the graph, run the following query against an empty Neo4j database: [source, cypher, role=test-setup] ---- -CREATE - (charlie:Person {name: 'Charlie Sheen'}), - (martin:Person {name: 'Martin Sheen'}), - (michael:Person {name: 'Michael Douglas'}), - (oliver:Person {name: 'Oliver Stone'}), - (rob:Person {name: 'Rob Reiner'}), - (wallStreet:Movie {title: 'Wall Street'}), - (charlie)-[:ACTED_IN {role: 'Bud Fox'}]->(wallStreet), - (martin)-[:ACTED_IN {role: 'Carl Fox'}]->(wallStreet), - (michael)-[:ACTED_IN {role: 'Gordon Gekko'}]->(wallStreet), - (oliver)-[:DIRECTED]->(wallStreet), - (thePresident:Movie {title: 'The American President'}), - (martin)-[:ACTED_IN {role: 'A.J. MacInerney'}]->(thePresident), - (michael)-[:ACTED_IN {role: 'President Andrew Shepherd'}]->(thePresident), - (rob)-[:DIRECTED]->(thePresident), - (martin)-[:FATHER_OF]->(charlie) +CREATE (charlie:Person {name: 'Charlie Sheen'}), + (martin:Person {name: 'Martin Sheen'}), + (michael:Person {name: 'Michael Douglas'}), + (oliver:Person {name: 'Oliver Stone'}), + (rob:Person {name: 'Rob Reiner'}), + (wallStreet:Movie {title: 'Wall Street'}), + (charlie)-[:ACTED_IN {role: 'Bud Fox'}]->(wallStreet), + (martin)-[:ACTED_IN {role: 'Carl Fox'}]->(wallStreet), + (michael)-[:ACTED_IN {role: 'Gordon Gekko'}]->(wallStreet), + (oliver)-[:DIRECTED]->(wallStreet), + (thePresident:Movie {title: 'The American President'}), + (martin)-[:ACTED_IN {role: 'A.J. MacInerney'}]->(thePresident), + (michael)-[:ACTED_IN {role: 'President Andrew Shepherd'}]->(thePresident), + (rob)-[:DIRECTED]->(thePresident) ---- +[[find-nodes]] +== Find nodes -[[basic-node-finding]] -== Basic node finding +The `MATCH` clause allows you to specify node patterns of varying complexity to retrieve from a graph. +For more information about finding node patterns, see xref:patterns/fixed-length-patterns#node-patterns[Patterns -> Node patterns]. -[[get-all-nodes]] -=== Get all nodes +[[find-all-nodes]] +=== Find all nodes By specifying a pattern with a single node and no labels, all nodes in the graph will be returned. -.Query -[source, cypher, indent=0] +.Find all nodes in a graph +[source, cypher] ---- MATCH (n) RETURN n ---- -Returns all the nodes in the database. - .Result [role="queryresult",options="header,footer",cols="1* +| "Martin Sheen" | +| "Michael Douglas" | +| "Oliver Stone" | +| "Rob Reiner" | +| | "Wall Street" +| | "The American President" +2+d| Rows: 7 |=== - -[[match-with-labels]] -=== Match with labels - -To constrain a pattern with labels on nodes, add the labels to the nodes in the pattern. - -.Query -[source, cypher, indent=0] +.Node pattern using negation (`!`) label expression +[source, cypher] ---- -MATCH (:Person {name: 'Oliver Stone'})--(movie:Movie) -RETURN movie.title +MATCH (n:!Movie) +RETURN labels(n) AS label, count(n) AS labelCount ---- -Returns any nodes with the `Movie` label connected to `Oliver Stone`. +[NOTE] +The above query uses the xref:functions/list.adoc#functions-labels[`labels()`] and xref:functions/aggregating.adoc#functions-count[`count()`] functions. .Result -[role="queryresult",options="header,footer",cols="1* Label expressions]. + +[[find-relationships]] +== Find relationships -[[label-expression-match-or-expression]] -=== Match with a label expression for the node labels +The `MATCH` clause allows you to specify relationship patterns of varying complexity to retrieve from a graph. +Unlike a node pattern, a relationship pattern cannot be used in a `MATCH` clause without node patterns at both ends. +For more information about relationship patterns, see xref:patterns/fixed-length-patterns#relationship patterns[Patterns -> Relationship patterns]. -A match with an `OR` expression for the node label returns the nodes that contains both the specified labels. +[NOTE] +Relationships will only be matched once inside a single pattern. +Read more about this behavior in the section on xref::patterns/reference.adoc#graph-patterns-rules-relationship-uniqueness[relationship uniqueness]. -.Query +[[empty-relationship-patterns]] +=== Empty relationship patterns + +By applying `--`, a pattern will be matched for a relationship with any direction and without any filtering on relationship types or properties. + +.Find connected nodes using an empty relationship pattern [source, cypher] ---- -MATCH (n:Movie|Person) -RETURN n.name AS name, n.title AS title +MATCH (:Person {name: 'Oliver Stone'})--(n) +RETURN n AS connectedNodes ---- .Result -[role="queryresult",options="header,footer",cols="2* -| "Martin Sheen" | -| "Michael Douglas" | -| "Oliver Stone" | -| "Rob Reiner" | -| | "Wall Street" -| | "The American President" -2+|Rows: 7 -|=== - +| connectedNodes +| (:Movie {title: "Wall Street"}) -[[relationship-basics]] -== Relationship basics +1+d| Rows: 1 +|=== -[[outgoing-relationships]] -=== Outgoing relationships +[[directed-relationship-patterns]] +=== Directed relationship patterns -When the direction of a relationship is of interest, it is shown by using `-->` or `<--`. -For example: +The direction of a relationship in a pattern is indicated by arrows: `-->` or `<--`. -.Query -[source, cypher, indent=0] +.Find all nodes connected to `Oliver Stone` by an outgoing relationship. +[source, cypher] ---- -MATCH (:Person {name: 'Oliver Stone'})-->(movie) -RETURN movie.title +MATCH (:Person {name: 'Oliver Stone'})-->(movie:Movie) +RETURN movie.title AS movieTitle ---- -Returns any nodes connected by an outgoing relationship to the `Person` node with the `name` property set to `Oliver Stone`. - .Result -[role="queryresult",options="header,footer",cols="1*(movie) -RETURN type(r) +MATCH (:Person {name: 'Oliver Stone'})-[r]->() +RETURN type(r) AS relType ---- -Returns the type of each outgoing relationship from `Oliver Stone`. +[NOTE] +The above query uses the xref:functions/scalar.adoc#functions-type[`type()` function]. .Result -[role="queryresult",options="header,footer",cols="1*()` will never match a relationship. + +For a list of all relationship type expressions supported by Cypher, see xref:patterns/reference.adoc#label-expressions[Patterns -> Label expressions]. + +[[multiple-relationships]] +=== Find multiple relationships + +A graph pattern can contain several relationship patterns. + +.Graph pattern including several relationship patterns +[source, cypher] +---- +MATCH (:Person {name: 'Charlie Sheen'})-[:ACTED_IN]->(movie:Movie)<-[:DIRECTED]-(director:Person) +RETURN movie.title AS movieTitle, director.name AS director +---- + +.Result +[role="queryresult",options="header,footer",cols="2*(movie:Movie) +WHERE charlie.name = 'Charlie Sheen' +RETURN movie.title AS movieTitle +---- -Variables and specific relationship types can be included in the same pattern. -For example: +.Result +[role="queryresult",options="header,footer",cols="1*(movie:Movie) +WHERE martin.name = 'Martin Sheen' AND NOT EXISTS { + MATCH (movie)<-[:DIRECTED]-(director:Person {name: 'Oliver Stone'}) +} +RETURN movie.title AS movieTitle ---- -Returns the `ACTED_IN` roles for the movie `Wall Street`. +[NOTE] +The above query uses an xref:subqueries/existential.adoc[`EXISTS` subquery]. .Result [role="queryresult",options="header,footer",cols="1* Parameters]. -Databases occasionally contain relationship types including non-alphanumerical characters, or with spaces in them. -These are created using backticks (```). +[[find-paths]] +== Find paths -For example, the following query creates a relationship which contains a space (`OLD FRIENDS`) between `Martin Sheen` and `Rob Reiner`. +The `MATCH` clause can also be used to bind whole paths to variables. -.Query -[source, cypher, indent=0] +.Find all paths matching a pattern +[source, cypher] ---- -MATCH - (martin:Person {name: 'Martin Sheen'}), - (rob:Person {name: 'Rob Reiner'}) -CREATE (rob)-[:`OLD FRIENDS`]->(martin) +MATCH path = ()-[:ACTED_IN]->(movie:Movie) +RETURN path ---- -This leads to the following graph: +.Result +[role="queryresult",options="header,footer",cols="1*(:Movie {title: "Wall Street"}) +| (:Person {name: "Martin Sheen"})-[:ACTED_IN {role: "Carl Fox"}]->(:Movie {title: "Wall Street"}) +| (:Person {name: "Martin Sheen"})-[:ACTED_IN {role: "A.J. MacInerney"}]->(:Movie {title: "The American President"}) +| (:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "Gordon Gekko"}]->(:Movie {title: "Wall Street"}) +| (:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "President Andrew Shepherd"}]->(:Movie {title: "The American President"}) +1+d| Rows: 5 +|=== -image::graph_match_clause_backtick.svg[width="600", role="middle"] -.Query -[source, cypher, indent=0] +.Find paths matching a pattern including a `WHERE` predicate +[source, cypher] ---- -MATCH (n {name: 'Rob Reiner'})-[r:`OLD FRIENDS`]->() -RETURN type(r) +MATCH path = (:Person)-[:ACTED_IN]->(movie:Movie)<-[:DIRECTED]-(:Person) +WHERE movie.title = 'Wall Street' +RETURN path ---- .Result [role="queryresult",options="header,footer",cols="1*(:Movie {title: "Wall Street"})<-[:DIRECTED]-(:Person {name: "Oliver Stone"}) +| (:Person {name: "Martin Sheen"})-[:ACTED_IN {role: "Carl Fox"}]->(:Movie {title: "Wall Street"})<-[:DIRECTED]-(:Person {name: "Oliver Stone"}) +| (:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "Gordon Gekko"}]->(:Movie {title: "Wall Street"})<-[:DIRECTED]-(:Person {name: "Oliver Stone"}) +1+d| Rows: 3 |=== +For more information about how `MATCH` is used to find patterns of varying complexity (including xref:patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path patterns], xref:patterns/variable-length-patterns.adoc#quantified-relationships[quantified relationships], and the xref:patterns/shortest-paths.adoc[shortest paths] between nodes), see the section on xref::patterns/index.adoc[Patterns]. -[[multiple-rels]] -=== Multiple relationships +== Multiple MATCH clauses, the WITH clause, and clause composition -Relationships can be expressed by using multiple statements in the form of `()--()`, or they can be strung together. -For example: +In Cypher, the behavior of a query is defined by its clauses. +Each clause takes the current graph state and a table of intermediate results, processes them, and passes the updated graph state and results to the next clause. +The first clause starts with the graph's initial state and an empty table, while the final clause produces the query result. -.Query -[source, cypher, indent=0] +.Chaining consecutive `MATCH` clauses +[source, cypher] ---- -MATCH (charlie {name: 'Charlie Sheen'})-[:ACTED_IN]->(movie)<-[:DIRECTED]-(director) -RETURN movie.title, director.name +MATCH (:Person {name: 'Martin Sheen'})-[:ACTED_IN]->(movie:Movie) // <1> +MATCH (director:Person)-[:DIRECTED]->(movie) // <2> +RETURN director.name AS director, movie.title AS movieTitle ---- - -Returns the movie in which `Charlie Sheen` acted and its director. +<1> The result of the first `MATCH` clause is the variable `movie` which holds all the `Movies` that `Martin Sheen` has `ACTED_IN`. +<2> The second `MATCH` clause uses the `movie` variable to find any `Person` node with a `DIRECTED` relationship to those `Movie` nodes that `Martin Sheen` has `ACTED_IN`. .Result [role="queryresult",options="header,footer",cols="2*(movies:Movie) // <1> +WITH actors, count(movies) AS movieCount // <2> +ORDER BY movieCount DESC +LIMIT 1 // <3> +MATCH (actors)-[:ACTED_IN]->(movies) // <4> +RETURN actors.name AS actor, movieCount, collect(movies.title) AS movies +---- +<1> The `Person` and `Movie` nodes matched in this step are stored in variables, which are then passed on to the second row of the query. +<2> The `movies` variable is implicitly imported by its occurrence in the `count()` function. +The `WITH` clause explicitly imports the `actors` variable. +<3> An xref:clauses/order-by.adoc[`ORDER BY`] clause orders the results by `movieCount` in descending order, ensuring that the `Person` with the highest number of movies appears at the top, and xref:clauses/limit.adoc[`LIMIT] 1` ensures that all other `Person` nodes are discarded. +<4> The second `MATCH` clause finds all `Movie` nodes associated with the `Person` nodes currently bound to the `actors` variable. + +[NOTE] +The above query uses the xref:functions/aggregating.adoc#functions-collect[`collect()` function]. + +.Result +[role="queryresult",options="header,footer",cols="3* Date: Wed, 30 Oct 2024 10:11:37 +0100 Subject: [PATCH 61/64] Small fix to MATCH (#1085) --- modules/ROOT/pages/clauses/match.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index f04bf857d..35f568d88 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -158,14 +158,13 @@ RETURN n AS connectedNodes |=== | connectedNodes | (:Movie {title: "Wall Street"}) - 1+d| Rows: 1 |=== [[directed-relationship-patterns]] === Directed relationship patterns -The direction of a relationship in a pattern is indicated by arrows: `-->` or `<--`. +The direction of a relationship in a pattern is indicated by arrows: `+-->+` or `+<--+`. .Find all nodes connected to `Oliver Stone` by an outgoing relationship. [source, cypher] From cdec96a8ffebdd83e047247c540689349aba0cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Wed, 30 Oct 2024 14:58:08 +0100 Subject: [PATCH 62/64] Remove mentions of Neo4j 6.0 (#1086) --- modules/ROOT/pages/functions/scalar.adoc | 8 ++++---- modules/ROOT/pages/syntax/naming.adoc | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/functions/scalar.adoc b/modules/ROOT/pages/functions/scalar.adoc index 459102044..8baa1844d 100644 --- a/modules/ROOT/pages/functions/scalar.adoc +++ b/modules/ROOT/pages/functions/scalar.adoc @@ -1205,12 +1205,12 @@ Future releases of Cypher may include updates to the current type system. This can include the introduction of new types and subtypes of already supported types. If a new type is introduced, it will be returned by the `valueType()` function as soon as it is released. However, if a more precise subtype of a previously supported type is introduced, it would be considered a breaking change. -As a result, any new subtypes introduced after the release of Neo4j 5.13 will not be returned by the `valueType()` function until the following major release (Neo4j 6.0). +As a result, any new subtypes introduced after the release of Neo4j 5.13 will not be returned by the `valueType()` function until the next major release of Neo4j. -For example, the function currently returns `"FLOAT"`, but if a more specific `FLOAT` type was added, e.g. `FLOAT32`, this would be considered more specific and not be returned until Neo4j 6.0. -As a result,`"FLOAT"` would continue to be returned for any `FLOAT32` values until the release of Neo4j 6.0. +For example, the function currently returns `"FLOAT"`, but if a more specific `FLOAT` type was added, e.g. `FLOAT32`, this would be considered more specific and not be returned until the next major release of Neo4j. +As a result,`"FLOAT"` would continue to be returned for any `FLOAT32` values until the next major release. -With this in mind, the below list contains all supported types (as of Neo4j 5.13) displayed by the `valueType()` function until the release of Neo4j 6.0: +With this in mind, the below list contains all supported types (as of Neo4j 5.13) displayed by the `valueType()` function until the next major release of Neo4j: * Predefined types ** `NOTHING` diff --git a/modules/ROOT/pages/syntax/naming.adoc b/modules/ROOT/pages/syntax/naming.adoc index d4b9357c1..6038ca3db 100644 --- a/modules/ROOT/pages/syntax/naming.adoc +++ b/modules/ROOT/pages/syntax/naming.adoc @@ -51,7 +51,8 @@ Some techniques to mitigate this are: [NOTE] ==== -Several special characters have been deprecated and will require escaping in Neo4j 6.0, see xref::deprecations-additions-removals-compatibility.adoc#cypher-deprecations-additions-removals-5.15[here] for the comprehensive list of deprecated characters. +Several special characters have been deprecated and will require escaping in the next major release of Neo4j. +For the comprehensive list of deprecated characters, see the xref::deprecations-additions-removals-compatibility.adoc#cypher-deprecations-additions-removals-5.15[deprecations page]. ==== == Scoping and namespace rules From e594babecb00b3ad2372a0a91544790248e0c670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:28:17 +0100 Subject: [PATCH 63/64] Fix cos() table (#1087) --- modules/ROOT/pages/functions/mathematical-trigonometric.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/functions/mathematical-trigonometric.adoc b/modules/ROOT/pages/functions/mathematical-trigonometric.adoc index 9382de300..dfdbfba26 100644 --- a/modules/ROOT/pages/functions/mathematical-trigonometric.adoc +++ b/modules/ROOT/pages/functions/mathematical-trigonometric.adoc @@ -186,8 +186,8 @@ The arctangent2 of `0.5` and `0.6` is returned. .Details |=== -| *Syntax* 3+| `acos(input)` -| *Description* 3+| Returns the arccosine of a `FLOAT` in radians. +| *Syntax* 3+| `cos(input)` +| *Description* 3+| Returns the cosine of a `FLOAT` in radians. .2+| *Arguments* | *Name* | *Type* | *Description* | `input` | `FLOAT` | An angle in radians. | *Returns* 3+| `FLOAT` From e2004250227b212b8bc19d2bbff767aa7d24b5d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 31 Oct 2024 10:24:26 +0100 Subject: [PATCH 64/64] add 5.25.1 --- antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/antora.yml b/antora.yml index ef51b64c7..37e37a897 100644 --- a/antora.yml +++ b/antora.yml @@ -8,4 +8,4 @@ asciidoc: attributes: neo4j-version: '5' neo4j-version-minor: '5.25' - neo4j-version-exact: '5.25.0' + neo4j-version-exact: '5.25.1'