From 008b88e4a9f9013dc7cc310d64ddd1966210de7e Mon Sep 17 00:00:00 2001 From: Alexey Palazhchenko Date: Mon, 11 Dec 2023 18:30:49 +0400 Subject: [PATCH] Add documentation for older versions (#3834) --- docker-compose.yml | 33 +- website/docusaurus.config-blog.js | 9 +- website/docusaurus.config.js | 12 +- website/src/pages/intro.js | 6 - website/src/pages/markdown-page.md | 7 - .../aggregation-operations/_category_.yml | 8 + .../aggregation-pipeline-and-commands.md | 77 ++ .../aggregation-stages.md | 19 + .../basic-operations/_category_.yml | 8 + .../version-v1.14/basic-operations/create.md | 80 ++ .../version-v1.14/basic-operations/delete.md | 88 +++ .../version-v1.14/basic-operations/index.md | 44 ++ .../version-v1.14/basic-operations/read.md | 197 +++++ .../version-v1.14/basic-operations/update.md | 205 +++++ .../configuration/_category_.yml | 10 + .../version-v1.14/configuration/flags.md | 114 +++ .../configuration/observability.md | 45 ++ .../configuration/operation-modes.md | 49 ++ .../version-v1.14/contributing/_category_.yml | 8 + .../version-v1.14/contributing/index.md | 48 ++ .../contributing/writing-guide.md | 144 ++++ website/versioned_docs/version-v1.14/diff.md | 32 + .../versioned_docs/version-v1.14/indexes.md | 140 ++++ website/versioned_docs/version-v1.14/main.md | 43 ++ .../version-v1.14/migration/_category_.yml | 8 + .../migration/migrating-from-mongodb.md | 66 ++ .../migration/premigration-testing.md | 233 ++++++ .../version-v1.14/operators/_category_.yml | 9 + .../operators/query/_category_.yml | 9 + .../operators/query/array-operators.md | 195 +++++ .../operators/query/bitwise-operators.md | 159 ++++ .../operators/query/comparison-operators.md | 383 +++++++++ .../operators/query/element-operators.md | 363 +++++++++ .../operators/query/evaluation-operators.md | 164 ++++ .../operators/query/logical-operators.md | 309 ++++++++ .../operators/update/_category_.yml | 9 + .../update/array-update-operators.md | 215 ++++++ .../update/field-update-operators.md | 370 +++++++++ .../versioned_docs/version-v1.14/pushdown.md | 54 ++ .../quickstart-guide/_category_.yml | 8 + .../version-v1.14/quickstart-guide/deb.md | 37 + .../version-v1.14/quickstart-guide/docker.md | 138 ++++ .../version-v1.14/quickstart-guide/go.md | 11 + .../version-v1.14/quickstart-guide/macos.md | 9 + .../version-v1.14/quickstart-guide/rpm.md | 36 + .../version-v1.14/quickstart-guide/windows.md | 9 + .../version-v1.14/reference/_category_.yml | 8 + .../version-v1.14/reference/glossary.md | 156 ++++ .../reference/supported-commands.md | 727 ++++++++++++++++++ .../version-v1.14/security/_category_.yml | 7 + .../version-v1.14/security/authentication.md | 105 +++ .../version-v1.14/security/tls-connections.md | 121 +++ .../versioned_docs/version-v1.14/telemetry.md | 153 ++++ .../version-v1.14/understanding-ferretdb.md | 197 +++++ .../aggregation-operations/_category_.yml | 8 + .../aggregation-pipeline-and-commands.md | 77 ++ .../aggregation-stages.md | 19 + .../basic-operations/_category_.yml | 8 + .../version-v1.15/basic-operations/create.md | 80 ++ .../version-v1.15/basic-operations/delete.md | 88 +++ .../version-v1.15/basic-operations/index.md | 44 ++ .../version-v1.15/basic-operations/read.md | 197 +++++ .../version-v1.15/basic-operations/update.md | 205 +++++ .../configuration/_category_.yml | 10 + .../version-v1.15/configuration/flags.md | 114 +++ .../configuration/observability.md | 45 ++ .../configuration/operation-modes.md | 49 ++ .../version-v1.15/contributing/_category_.yml | 8 + .../version-v1.15/contributing/index.md | 48 ++ .../contributing/writing-guide.md | 144 ++++ website/versioned_docs/version-v1.15/diff.md | 32 + .../versioned_docs/version-v1.15/indexes.md | 140 ++++ website/versioned_docs/version-v1.15/main.md | 43 ++ .../version-v1.15/migration/_category_.yml | 8 + .../migration/migrating-from-mongodb.md | 66 ++ .../migration/premigration-testing.md | 233 ++++++ .../version-v1.15/operators/_category_.yml | 9 + .../operators/query/_category_.yml | 9 + .../operators/query/array-operators.md | 195 +++++ .../operators/query/bitwise-operators.md | 159 ++++ .../operators/query/comparison-operators.md | 383 +++++++++ .../operators/query/element-operators.md | 363 +++++++++ .../operators/query/evaluation-operators.md | 164 ++++ .../operators/query/logical-operators.md | 309 ++++++++ .../operators/update/_category_.yml | 9 + .../update/array-update-operators.md | 215 ++++++ .../update/field-update-operators.md | 370 +++++++++ .../versioned_docs/version-v1.15/pushdown.md | 54 ++ .../quickstart-guide/_category_.yml | 8 + .../version-v1.15/quickstart-guide/deb.md | 37 + .../version-v1.15/quickstart-guide/docker.md | 138 ++++ .../version-v1.15/quickstart-guide/go.md | 11 + .../version-v1.15/quickstart-guide/macos.md | 9 + .../version-v1.15/quickstart-guide/rpm.md | 36 + .../version-v1.15/quickstart-guide/windows.md | 9 + .../version-v1.15/reference/_category_.yml | 8 + .../version-v1.15/reference/glossary.md | 156 ++++ .../reference/supported-commands.md | 727 ++++++++++++++++++ .../version-v1.15/security/_category_.yml | 7 + .../version-v1.15/security/authentication.md | 105 +++ .../version-v1.15/security/tls-connections.md | 121 +++ .../versioned_docs/version-v1.15/telemetry.md | 153 ++++ .../version-v1.15/understanding-ferretdb.md | 197 +++++ .../aggregation-operations/_category_.yml | 8 + .../aggregation-pipeline-and-commands.md | 77 ++ .../aggregation-stages.md | 19 + .../basic-operations/_category_.yml | 8 + .../version-v1.16/basic-operations/create.md | 80 ++ .../version-v1.16/basic-operations/delete.md | 88 +++ .../version-v1.16/basic-operations/index.md | 44 ++ .../version-v1.16/basic-operations/read.md | 197 +++++ .../version-v1.16/basic-operations/update.md | 205 +++++ .../configuration/_category_.yml | 10 + .../version-v1.16/configuration/flags.md | 114 +++ .../configuration/observability.md | 45 ++ .../configuration/operation-modes.md | 49 ++ .../version-v1.16/contributing/_category_.yml | 8 + .../version-v1.16/contributing/index.md | 48 ++ .../contributing/writing-guide.md | 144 ++++ website/versioned_docs/version-v1.16/diff.md | 32 + .../versioned_docs/version-v1.16/indexes.md | 140 ++++ website/versioned_docs/version-v1.16/main.md | 43 ++ .../version-v1.16/migration/_category_.yml | 8 + .../migration/migrating-from-mongodb.md | 66 ++ .../migration/premigration-testing.md | 233 ++++++ .../version-v1.16/operators/_category_.yml | 9 + .../operators/query/_category_.yml | 9 + .../operators/query/array-operators.md | 195 +++++ .../operators/query/bitwise-operators.md | 159 ++++ .../operators/query/comparison-operators.md | 383 +++++++++ .../operators/query/element-operators.md | 363 +++++++++ .../operators/query/evaluation-operators.md | 164 ++++ .../operators/query/logical-operators.md | 309 ++++++++ .../operators/update/_category_.yml | 9 + .../update/array-update-operators.md | 215 ++++++ .../update/field-update-operators.md | 370 +++++++++ .../versioned_docs/version-v1.16/pushdown.md | 54 ++ .../quickstart-guide/_category_.yml | 8 + .../version-v1.16/quickstart-guide/deb.md | 37 + .../version-v1.16/quickstart-guide/docker.md | 138 ++++ .../version-v1.16/quickstart-guide/go.md | 11 + .../version-v1.16/quickstart-guide/macos.md | 9 + .../version-v1.16/quickstart-guide/rpm.md | 36 + .../version-v1.16/quickstart-guide/windows.md | 9 + .../version-v1.16/reference/_category_.yml | 8 + .../version-v1.16/reference/glossary.md | 156 ++++ .../reference/supported-commands.md | 727 ++++++++++++++++++ .../version-v1.16/security/_category_.yml | 7 + .../version-v1.16/security/authentication.md | 105 +++ .../version-v1.16/security/tls-connections.md | 121 +++ .../versioned_docs/version-v1.16/telemetry.md | 153 ++++ .../version-v1.16/understanding-ferretdb.md | 197 +++++ .../version-v1.14-sidebars.json | 8 + .../version-v1.15-sidebars.json | 8 + .../version-v1.16-sidebars.json | 8 + website/versions.json | 3 + 156 files changed, 16935 insertions(+), 40 deletions(-) delete mode 100644 website/src/pages/intro.js delete mode 100644 website/src/pages/markdown-page.md create mode 100644 website/versioned_docs/version-v1.14/aggregation-operations/_category_.yml create mode 100644 website/versioned_docs/version-v1.14/aggregation-operations/aggregation-pipeline-and-commands.md create mode 100644 website/versioned_docs/version-v1.14/aggregation-operations/aggregation-stages.md create mode 100644 website/versioned_docs/version-v1.14/basic-operations/_category_.yml create mode 100644 website/versioned_docs/version-v1.14/basic-operations/create.md create mode 100644 website/versioned_docs/version-v1.14/basic-operations/delete.md create mode 100644 website/versioned_docs/version-v1.14/basic-operations/index.md create mode 100644 website/versioned_docs/version-v1.14/basic-operations/read.md create mode 100644 website/versioned_docs/version-v1.14/basic-operations/update.md create mode 100644 website/versioned_docs/version-v1.14/configuration/_category_.yml create mode 100644 website/versioned_docs/version-v1.14/configuration/flags.md create mode 100644 website/versioned_docs/version-v1.14/configuration/observability.md create mode 100644 website/versioned_docs/version-v1.14/configuration/operation-modes.md create mode 100644 website/versioned_docs/version-v1.14/contributing/_category_.yml create mode 100644 website/versioned_docs/version-v1.14/contributing/index.md create mode 100644 website/versioned_docs/version-v1.14/contributing/writing-guide.md create mode 100644 website/versioned_docs/version-v1.14/diff.md create mode 100644 website/versioned_docs/version-v1.14/indexes.md create mode 100644 website/versioned_docs/version-v1.14/main.md create mode 100644 website/versioned_docs/version-v1.14/migration/_category_.yml create mode 100644 website/versioned_docs/version-v1.14/migration/migrating-from-mongodb.md create mode 100644 website/versioned_docs/version-v1.14/migration/premigration-testing.md create mode 100644 website/versioned_docs/version-v1.14/operators/_category_.yml create mode 100644 website/versioned_docs/version-v1.14/operators/query/_category_.yml create mode 100644 website/versioned_docs/version-v1.14/operators/query/array-operators.md create mode 100644 website/versioned_docs/version-v1.14/operators/query/bitwise-operators.md create mode 100644 website/versioned_docs/version-v1.14/operators/query/comparison-operators.md create mode 100644 website/versioned_docs/version-v1.14/operators/query/element-operators.md create mode 100644 website/versioned_docs/version-v1.14/operators/query/evaluation-operators.md create mode 100644 website/versioned_docs/version-v1.14/operators/query/logical-operators.md create mode 100644 website/versioned_docs/version-v1.14/operators/update/_category_.yml create mode 100644 website/versioned_docs/version-v1.14/operators/update/array-update-operators.md create mode 100644 website/versioned_docs/version-v1.14/operators/update/field-update-operators.md create mode 100644 website/versioned_docs/version-v1.14/pushdown.md create mode 100644 website/versioned_docs/version-v1.14/quickstart-guide/_category_.yml create mode 100644 website/versioned_docs/version-v1.14/quickstart-guide/deb.md create mode 100644 website/versioned_docs/version-v1.14/quickstart-guide/docker.md create mode 100644 website/versioned_docs/version-v1.14/quickstart-guide/go.md create mode 100644 website/versioned_docs/version-v1.14/quickstart-guide/macos.md create mode 100644 website/versioned_docs/version-v1.14/quickstart-guide/rpm.md create mode 100644 website/versioned_docs/version-v1.14/quickstart-guide/windows.md create mode 100644 website/versioned_docs/version-v1.14/reference/_category_.yml create mode 100644 website/versioned_docs/version-v1.14/reference/glossary.md create mode 100644 website/versioned_docs/version-v1.14/reference/supported-commands.md create mode 100644 website/versioned_docs/version-v1.14/security/_category_.yml create mode 100644 website/versioned_docs/version-v1.14/security/authentication.md create mode 100644 website/versioned_docs/version-v1.14/security/tls-connections.md create mode 100644 website/versioned_docs/version-v1.14/telemetry.md create mode 100644 website/versioned_docs/version-v1.14/understanding-ferretdb.md create mode 100644 website/versioned_docs/version-v1.15/aggregation-operations/_category_.yml create mode 100644 website/versioned_docs/version-v1.15/aggregation-operations/aggregation-pipeline-and-commands.md create mode 100644 website/versioned_docs/version-v1.15/aggregation-operations/aggregation-stages.md create mode 100644 website/versioned_docs/version-v1.15/basic-operations/_category_.yml create mode 100644 website/versioned_docs/version-v1.15/basic-operations/create.md create mode 100644 website/versioned_docs/version-v1.15/basic-operations/delete.md create mode 100644 website/versioned_docs/version-v1.15/basic-operations/index.md create mode 100644 website/versioned_docs/version-v1.15/basic-operations/read.md create mode 100644 website/versioned_docs/version-v1.15/basic-operations/update.md create mode 100644 website/versioned_docs/version-v1.15/configuration/_category_.yml create mode 100644 website/versioned_docs/version-v1.15/configuration/flags.md create mode 100644 website/versioned_docs/version-v1.15/configuration/observability.md create mode 100644 website/versioned_docs/version-v1.15/configuration/operation-modes.md create mode 100644 website/versioned_docs/version-v1.15/contributing/_category_.yml create mode 100644 website/versioned_docs/version-v1.15/contributing/index.md create mode 100644 website/versioned_docs/version-v1.15/contributing/writing-guide.md create mode 100644 website/versioned_docs/version-v1.15/diff.md create mode 100644 website/versioned_docs/version-v1.15/indexes.md create mode 100644 website/versioned_docs/version-v1.15/main.md create mode 100644 website/versioned_docs/version-v1.15/migration/_category_.yml create mode 100644 website/versioned_docs/version-v1.15/migration/migrating-from-mongodb.md create mode 100644 website/versioned_docs/version-v1.15/migration/premigration-testing.md create mode 100644 website/versioned_docs/version-v1.15/operators/_category_.yml create mode 100644 website/versioned_docs/version-v1.15/operators/query/_category_.yml create mode 100644 website/versioned_docs/version-v1.15/operators/query/array-operators.md create mode 100644 website/versioned_docs/version-v1.15/operators/query/bitwise-operators.md create mode 100644 website/versioned_docs/version-v1.15/operators/query/comparison-operators.md create mode 100644 website/versioned_docs/version-v1.15/operators/query/element-operators.md create mode 100644 website/versioned_docs/version-v1.15/operators/query/evaluation-operators.md create mode 100644 website/versioned_docs/version-v1.15/operators/query/logical-operators.md create mode 100644 website/versioned_docs/version-v1.15/operators/update/_category_.yml create mode 100644 website/versioned_docs/version-v1.15/operators/update/array-update-operators.md create mode 100644 website/versioned_docs/version-v1.15/operators/update/field-update-operators.md create mode 100644 website/versioned_docs/version-v1.15/pushdown.md create mode 100644 website/versioned_docs/version-v1.15/quickstart-guide/_category_.yml create mode 100644 website/versioned_docs/version-v1.15/quickstart-guide/deb.md create mode 100644 website/versioned_docs/version-v1.15/quickstart-guide/docker.md create mode 100644 website/versioned_docs/version-v1.15/quickstart-guide/go.md create mode 100644 website/versioned_docs/version-v1.15/quickstart-guide/macos.md create mode 100644 website/versioned_docs/version-v1.15/quickstart-guide/rpm.md create mode 100644 website/versioned_docs/version-v1.15/quickstart-guide/windows.md create mode 100644 website/versioned_docs/version-v1.15/reference/_category_.yml create mode 100644 website/versioned_docs/version-v1.15/reference/glossary.md create mode 100644 website/versioned_docs/version-v1.15/reference/supported-commands.md create mode 100644 website/versioned_docs/version-v1.15/security/_category_.yml create mode 100644 website/versioned_docs/version-v1.15/security/authentication.md create mode 100644 website/versioned_docs/version-v1.15/security/tls-connections.md create mode 100644 website/versioned_docs/version-v1.15/telemetry.md create mode 100644 website/versioned_docs/version-v1.15/understanding-ferretdb.md create mode 100644 website/versioned_docs/version-v1.16/aggregation-operations/_category_.yml create mode 100644 website/versioned_docs/version-v1.16/aggregation-operations/aggregation-pipeline-and-commands.md create mode 100644 website/versioned_docs/version-v1.16/aggregation-operations/aggregation-stages.md create mode 100644 website/versioned_docs/version-v1.16/basic-operations/_category_.yml create mode 100644 website/versioned_docs/version-v1.16/basic-operations/create.md create mode 100644 website/versioned_docs/version-v1.16/basic-operations/delete.md create mode 100644 website/versioned_docs/version-v1.16/basic-operations/index.md create mode 100644 website/versioned_docs/version-v1.16/basic-operations/read.md create mode 100644 website/versioned_docs/version-v1.16/basic-operations/update.md create mode 100644 website/versioned_docs/version-v1.16/configuration/_category_.yml create mode 100644 website/versioned_docs/version-v1.16/configuration/flags.md create mode 100644 website/versioned_docs/version-v1.16/configuration/observability.md create mode 100644 website/versioned_docs/version-v1.16/configuration/operation-modes.md create mode 100644 website/versioned_docs/version-v1.16/contributing/_category_.yml create mode 100644 website/versioned_docs/version-v1.16/contributing/index.md create mode 100644 website/versioned_docs/version-v1.16/contributing/writing-guide.md create mode 100644 website/versioned_docs/version-v1.16/diff.md create mode 100644 website/versioned_docs/version-v1.16/indexes.md create mode 100644 website/versioned_docs/version-v1.16/main.md create mode 100644 website/versioned_docs/version-v1.16/migration/_category_.yml create mode 100644 website/versioned_docs/version-v1.16/migration/migrating-from-mongodb.md create mode 100644 website/versioned_docs/version-v1.16/migration/premigration-testing.md create mode 100644 website/versioned_docs/version-v1.16/operators/_category_.yml create mode 100644 website/versioned_docs/version-v1.16/operators/query/_category_.yml create mode 100644 website/versioned_docs/version-v1.16/operators/query/array-operators.md create mode 100644 website/versioned_docs/version-v1.16/operators/query/bitwise-operators.md create mode 100644 website/versioned_docs/version-v1.16/operators/query/comparison-operators.md create mode 100644 website/versioned_docs/version-v1.16/operators/query/element-operators.md create mode 100644 website/versioned_docs/version-v1.16/operators/query/evaluation-operators.md create mode 100644 website/versioned_docs/version-v1.16/operators/query/logical-operators.md create mode 100644 website/versioned_docs/version-v1.16/operators/update/_category_.yml create mode 100644 website/versioned_docs/version-v1.16/operators/update/array-update-operators.md create mode 100644 website/versioned_docs/version-v1.16/operators/update/field-update-operators.md create mode 100644 website/versioned_docs/version-v1.16/pushdown.md create mode 100644 website/versioned_docs/version-v1.16/quickstart-guide/_category_.yml create mode 100644 website/versioned_docs/version-v1.16/quickstart-guide/deb.md create mode 100644 website/versioned_docs/version-v1.16/quickstart-guide/docker.md create mode 100644 website/versioned_docs/version-v1.16/quickstart-guide/go.md create mode 100644 website/versioned_docs/version-v1.16/quickstart-guide/macos.md create mode 100644 website/versioned_docs/version-v1.16/quickstart-guide/rpm.md create mode 100644 website/versioned_docs/version-v1.16/quickstart-guide/windows.md create mode 100644 website/versioned_docs/version-v1.16/reference/_category_.yml create mode 100644 website/versioned_docs/version-v1.16/reference/glossary.md create mode 100644 website/versioned_docs/version-v1.16/reference/supported-commands.md create mode 100644 website/versioned_docs/version-v1.16/security/_category_.yml create mode 100644 website/versioned_docs/version-v1.16/security/authentication.md create mode 100644 website/versioned_docs/version-v1.16/security/tls-connections.md create mode 100644 website/versioned_docs/version-v1.16/telemetry.md create mode 100644 website/versioned_docs/version-v1.16/understanding-ferretdb.md create mode 100644 website/versioned_sidebars/version-v1.14-sidebars.json create mode 100644 website/versioned_sidebars/version-v1.15-sidebars.json create mode 100644 website/versioned_sidebars/version-v1.16-sidebars.json diff --git a/docker-compose.yml b/docker-compose.yml index d5d7467b58e5..2dc05b4b9ee9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -186,19 +186,20 @@ services: ports: - 3000:3000 volumes: - - ./website/docs:/workdir/docusaurus-docs/docs:ro + # shared with blog + - ./website/babel.config.js:/workdir/docusaurus-docs/babel.config.js:ro + - ./website/sidebars.js:/workdir/docusaurus-docs/sidebars.js:ro + - ./website/src:/workdir/docusaurus-docs/src:ro - ./website/static:/workdir/docusaurus-docs/static:ro - - ./website/src/components:/workdir/docusaurus-docs/src/components:ro - - ./website/src/css:/workdir/docusaurus-docs/src/css:ro - - # We copy intro.js to redirect from /intro (old default docs page) to the root docs page. - - ./website/src/pages/intro.js:/workdir/docusaurus-docs/src/pages/intro.js + - ./website/build:/workdir/docusaurus-docs/build:rw - - ./website/babel.config.js:/workdir/docusaurus-docs/babel.config.js:ro + # docs sources + - ./website/docs:/workdir/docusaurus-docs/docs:rw - ./website/docusaurus.config.js:/workdir/docusaurus-docs/docusaurus.config.js:ro - - ./website/sidebars.js:/workdir/docusaurus-docs/sidebars.js:ro + - ./website/versioned_docs:/workdir/docusaurus-docs/versioned_docs:rw + - ./website/versioned_sidebars:/workdir/docusaurus-docs/versioned_sidebars:rw + - ./website/versions.json:/workdir/docusaurus-docs/versions.json:rw - - ./website/build:/workdir/docusaurus-docs/build:rw docusaurus-blog: build: context: ./build/deps @@ -207,17 +208,17 @@ services: ports: - 3001:3001 volumes: - - ./website/blog:/workdir/docusaurus-docs/blog:ro - - ./website/static:/workdir/docusaurus-docs/static:ro - - ./website/src/components:/workdir/docusaurus-docs/src/components:ro - - ./website/src/css:/workdir/docusaurus-docs/src/css:ro - + # shared with docs - ./website/babel.config.js:/workdir/docusaurus-docs/babel.config.js:ro - - ./website/docusaurus.config-blog.js:/workdir/docusaurus-docs/docusaurus.config.js:ro - ./website/sidebars.js:/workdir/docusaurus-docs/sidebars.js:ro - + - ./website/src:/workdir/docusaurus-docs/src:ro + - ./website/static:/workdir/docusaurus-docs/static:ro - ./website/build:/workdir/docusaurus-docs/build:rw + # blog sources + - ./website/blog:/workdir/docusaurus-docs/blog:ro + - ./website/docusaurus.config-blog.js:/workdir/docusaurus-docs/docusaurus.config.js:ro + networks: default: name: ferretdb diff --git a/website/docusaurus.config-blog.js b/website/docusaurus.config-blog.js index 0611c3e8c6ba..04a46cff1c78 100644 --- a/website/docusaurus.config-blog.js +++ b/website/docusaurus.config-blog.js @@ -104,11 +104,6 @@ const config = { srcDark: 'img/logo-light.png' }, items: [ - { - to: '/', - label: 'Blog', - position: 'left' - }, { href: 'https://docs.ferretdb.io/', position: 'right', @@ -167,6 +162,10 @@ const config = { label: 'FerretDB.com', position: 'right', }, + { + label: 'Blog', + to: '/', + }, { label: 'GitHub', href: 'https://github.com/FerretDB/', diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 6664979af77a..ed639034fcbd 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -44,12 +44,12 @@ const config = { sidebarPath: require.resolve('./sidebars.js'), editUrl: 'https://github.com/FerretDB/FerretDB/tree/main/website', - // versions: { - // // the latest minus one minor - // 'v1.15': { - // banner: 'none', - // }, - // }, + versions: { + // the latest minus one minor + 'v1.15': { + banner: 'none', + }, + }, }, theme: { customCss: require.resolve('./src/css/custom.css'), diff --git a/website/src/pages/intro.js b/website/src/pages/intro.js deleted file mode 100644 index 94936b895168..000000000000 --- a/website/src/pages/intro.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import {Redirect} from '@docusaurus/router'; - -export default function Home() { - return ; -}; diff --git a/website/src/pages/markdown-page.md b/website/src/pages/markdown-page.md deleted file mode 100644 index c14765afc17c..000000000000 --- a/website/src/pages/markdown-page.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Markdown page example ---- - -## Markdown page example - -You don't need React to write simple standalone pages. diff --git a/website/versioned_docs/version-v1.14/aggregation-operations/_category_.yml b/website/versioned_docs/version-v1.14/aggregation-operations/_category_.yml new file mode 100644 index 000000000000..f6e53577a0e8 --- /dev/null +++ b/website/versioned_docs/version-v1.14/aggregation-operations/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Aggregation Operations +position: 6 +link: + type: generated-index + slug: /aggregation-operations/ + description: > + This section details aggregation operations in FerretDB, including aggregation commands, stages, and operators diff --git a/website/versioned_docs/version-v1.14/aggregation-operations/aggregation-pipeline-and-commands.md b/website/versioned_docs/version-v1.14/aggregation-operations/aggregation-pipeline-and-commands.md new file mode 100644 index 000000000000..afacda117a23 --- /dev/null +++ b/website/versioned_docs/version-v1.14/aggregation-operations/aggregation-pipeline-and-commands.md @@ -0,0 +1,77 @@ +--- +sidebar_position: 1 +--- + +# Aggregation pipeline and commands + +Aggregation operations involve performing various operations on a large number of data records, such as data grouping, sorting, restructuring, or modifying. +These operations pass through one or more stages, which make up a pipeline. + +![aggregation stages](/img/docs/aggregation-stages.jpg) + +Each stage acts upon the returned documents of the previous stage, starting with the input documents. +As shown above, the documents pass through the pipeline with the result of the previous stage acting as input for the next stage, going from `$match` => `$group` => `$sort` stage. + +For example, insert the following documents in a `sales` collection: + +```js +db.sales.insertMany([ + { _id: 1, category: 'Electronics', price: 1000 }, + { _id: 2, category: 'Electronics', price: 800 }, + { _id: 3, category: 'Clothing', price: 30 }, + { _id: 4, category: 'Clothing', price: 50 }, + { _id: 5, category: 'Home', price: 1500 }, + { _id: 6, category: 'Home', price: 1200 }, + { _id: 7, category: 'Books', price: 20 }, + { _id: 8, category: 'Books', price: 40 } +]) +``` + +A typical aggregation pipeline would look like this: + +```js +db.sales.aggregate([ + { $match: { category: { $ne: 'Electronics' } } }, + { + $group: { + _id: '$category', + totalPrice: { $sum: '$price' }, + productCount: { $sum: 1 } + } + }, + { $sort: { totalPrice: -1 } } +]) +``` + +In the pipeline, the complex query is broken down into separate stages where the record goes through a series of transformations until it finally produces the desired result. +First, the `$match` stage filters out all documents where the `category` field is not `Electronics`. +Then, the `$group` stage groups the documents by their `category` and calculates the total price and product count for each of those category. +Finally, the `$sort` stage sorts the documents by the `totalPrice` field in descending order. + +So the above aggregation pipeline operation would return the following result: + +```json5 +[ + { _id: 'Home', totalPrice: 2700, productCount: 2 }, + { _id: 'Clothing', totalPrice: 80, productCount: 2 }, + { _id: 'Books', totalPrice: 60, productCount: 2 } +] +``` + +This section of the documentation will focus on [`aggregate` command](#aggregate-command), [aggregation stages](aggregation-stages.md), and aggregation operators. + +## `aggregate` command + +The aggregation command `aggregate` is a top-level command used for aggregating data across various pipeline stages. + +The command is used for performing aggregation operations on a collection and lets you specify aggregation operations in a pipeline consisting of one or more stages and operators for transforming and analyzing data, such as grouping, filtering, sorting, projecting, and calculating aggregates. + +```js +// Aggregation pipeline to perform aggregation operations on a collection +db.collection.aggregate([ + // Stage 1: Matching documents based on a specific field and value + { $match: { field: value } }, + // Stage 2: Grouping documents by the "category" field and calculating the sum of the "quantity" field + { $group: { _id: '$category', total: { $sum: '$quantity' } } } +]) +``` diff --git a/website/versioned_docs/version-v1.14/aggregation-operations/aggregation-stages.md b/website/versioned_docs/version-v1.14/aggregation-operations/aggregation-stages.md new file mode 100644 index 000000000000..1b27aa0a1c30 --- /dev/null +++ b/website/versioned_docs/version-v1.14/aggregation-operations/aggregation-stages.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 2 +--- + +# Aggregation stages + +Aggregation stages are a series of one or more processes in a pipeline that acts upon the returned result of the previous stage, starting with the input documents. + +| Supported aggregation stages | Description | +| ---------------------------- | ----------------------------------------------------------------------------------------------------- | +| `$count` | Returns the count of all matched documents in a specified query | +| `$group` | Groups documents based on specific value or expression and returns a single document for each group | +| `$limit` | Limits specific documents and passes the rest to the next stage | +| `$match` | Acts as a `find` operation by only returning documents that match a specified query to the next stage | +| `$project` | Specifies the fields in a document to pass to the next stage in the pipeline | +| `$skip` | Skips a specified `n` number of documents and passes the rest to the next stage | +| `$sort` | Sorts and returns all the documents based on a specified order | +| `$unset` | Specifies the fields to be removed/excluded from a document | +| `$unwind` | Deconstructs and returns a document for every element in an array field | diff --git a/website/versioned_docs/version-v1.14/basic-operations/_category_.yml b/website/versioned_docs/version-v1.14/basic-operations/_category_.yml new file mode 100644 index 000000000000..0efa62204a79 --- /dev/null +++ b/website/versioned_docs/version-v1.14/basic-operations/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Basic CRUD Operations +position: 4 +link: + type: generated-index + slug: /basic-operations/ + description: > + Perform basic CRUD operations using FerretDB diff --git a/website/versioned_docs/version-v1.14/basic-operations/create.md b/website/versioned_docs/version-v1.14/basic-operations/create.md new file mode 100644 index 000000000000..d524b993bab2 --- /dev/null +++ b/website/versioned_docs/version-v1.14/basic-operations/create.md @@ -0,0 +1,80 @@ +--- +sidebar_position: 2 +--- + +# Insert operation + +The insert operation adds a new document to a collection. + +## Insert a single document + +The `insertOne()` command is used to add a single document into a collection, using this syntax format: + +```js +db.collection.insertOne({field1: value1, field2: value2,.... fieldN: valueN}) +``` + +The example below depicts how a single document can be added to a collection. +If a collection does not exist, the insert command automatically creates one. + +```js +db.scientists.insertOne({ + name: { + firstname: 'Thomas', + lastname: 'Edison' + }, + born: 1847, + invention: 'lightbulb' +}) +``` + +If the operation is successful, you will get a response with acknowledged set to true, and the autogenerated ObjectId of the document that looks like this: + +```js +{ + acknowledged: true, + insertedId: ObjectId("6346fcafd7a4a1b0b38eb2db") +} +``` + +## Insert multiple documents at once + +A collection can contain multiple documents. +Using the `insertMany()` command, you can add multiple documents to a collection at once. + +```js +db.collection_name.insertMany([{ document1 }, { document2 }, ...{ documentN }]) +``` + +The following example shows how to insert multiple documents into a collection: + +```js +db.scientists.insertMany([ + { + name: { + firstname: 'Alan', + lastname: 'Turing' + }, + born: 1912, + invention: 'Turing Machine' + }, + { + name: { + firstname: 'Graham', + lastname: 'Bell' + }, + born: 1847, + invention: 'telephone' + }, + { + name: { + firstname: 'Ada', + lastname: 'Lovelace' + }, + born: 1815, + invention: 'computer programming' + } +]) +``` + +You can retrieve all the documents in the collection with this command: `db.scientists.find({})` diff --git a/website/versioned_docs/version-v1.14/basic-operations/delete.md b/website/versioned_docs/version-v1.14/basic-operations/delete.md new file mode 100644 index 000000000000..50bda975115a --- /dev/null +++ b/website/versioned_docs/version-v1.14/basic-operations/delete.md @@ -0,0 +1,88 @@ +--- +sidebar_position: 5 +--- + +# Delete operation + +The delete operation removes a document from the database when a given query is met. +Two methods for deleting documents in a collection include `deleteOne()` and `deleteMany()`. + +## Delete a single document + +The `deleteOne()` method removes a single document (the first document that matches the query parameter) completely from the collection. + +```js +db.collection.deleteOne({}) +``` + +Insert the following list of documents: + +```js +db.scientists.insertMany([ + { + firstname: 'Thomas', + lastname: 'Edison', + born: 1847, + invention: 'LightBulb', + nobel: true + }, + { + firstname: 'Graham', + lastname: 'Bell', + born: 1847, + invention: 'telephone', + nobel: false + }, + { + firstname: 'Nikola', + lastname: 'Tesla', + born: 1856, + invention: 'Tesla coil', + nobel: false + }, + { + firstname: 'Ada', + lastname: 'Lovelace', + born: 1815, + invention: 'Computer programming', + nobel: false + } +]) +``` + +This operation returns a response showing `acknowledged` as `true` and the `ObjectId` of the four inserted documents: + +```js +{ + acknowledged: true, + insertedIds: { + '0': ObjectId("63470121d7a4a1b0b38eb2df"), + '1': ObjectId("63470121d7a4a1b0b38eb2e0"), + '2': ObjectId("63470121d7a4a1b0b38eb2e1"), + '3': ObjectId("63470121d7a4a1b0b38eb2e2") + } +} +``` + +Next, delete a document from the collection where the field `nobel` is set to false. + +```js +db.scientists.deleteOne({ nobel: false }) +``` + +This operation returns a response that shows that a single document was deleted from the collection. + +```js +{ acknowledged: true, deletedCount: 1 } +``` + +## Deletes multiple documents + +To delete multiple documents at once, use the `deleteMany()` method. +Using the same record from earlier, let's delete all the documents with `nobel` set to false. + +```js +db.scientists.deleteMany({ nobel: false }) +``` + +This command removes all the documents in the collection that matches the query. diff --git a/website/versioned_docs/version-v1.14/basic-operations/index.md b/website/versioned_docs/version-v1.14/basic-operations/index.md new file mode 100644 index 000000000000..a125d1eaa0a4 --- /dev/null +++ b/website/versioned_docs/version-v1.14/basic-operations/index.md @@ -0,0 +1,44 @@ +--- +sidebar_position: 1 +slug: /crud-operations/ +--- + +# Performing CRUD operations + +CRUD (Create, Read, Update, and Delete) operations in FerretDB use the same protocol and drivers as MongoDB. + +## Create operations in FerretDB + +The create operation adds a new document to a collection. +If the collection does not exist, this operation will create it. +The following methods are available for adding documents to a collection: + +[`db.collection.insertOne()`](create.md#insert-a-single-document), +[`db.collection.insertMany()`](create.md#insert-multiple-documents-at-once) + +## Read operations in FerretDB + +The read operation retrieves document records in a collection. +You can also filter the documents by targeting specific criteria for retrieval. +The following commands are used to retrieve documents from a collection: + +[`db.collection.find()`](read.md#retrieve-all-documents-in-a-collection), [`db.collection.findOne()`](read.md#retrieve-a-single-document) + +The read operation can also retrieve subdocuments that are nested within a document. + +## Update operations in FerretDB + +The update operation modifies document records in a collection. +It changes existing documents in a collection according to the query criteria. +The following update operations are supported: + +[`db.collection.updateOne()`](update.md#update-a-single-document), [`db.collection.updateMany()`](update.md#update-many-documents), [`db.collection.replaceOne()`](update#replace-a-document) + +## Delete operations in FerretDB + +The delete operation removes document records from a collection. +The following delete operations are supported: + +[`db.collection.deleteOne()`](delete.md#delete-a-single-document), [`db.collection.deleteMany()`](delete.md#deletes-multiple-documents) + +Similar to the update operation, this operation retrieves documents matching specific criteria in a collection and deletes them. diff --git a/website/versioned_docs/version-v1.14/basic-operations/read.md b/website/versioned_docs/version-v1.14/basic-operations/read.md new file mode 100644 index 000000000000..bc43096aaa90 --- /dev/null +++ b/website/versioned_docs/version-v1.14/basic-operations/read.md @@ -0,0 +1,197 @@ +--- +sidebar_position: 3 +--- + +# Read operation + +The read operation retrieves documents in a collection. +You can either retrieve all the documents in a collection, or only the documents that match a given query parameter. + +## Retrieve a single document + +The `findOne()` command retrieves a single document from a collection. + +First, populate the database with a new collection containing a list of documents. + +```js +db.scientists.insertMany([ + { + name: { + firstname: 'Alan', + lastname: 'Turing' + }, + born: 1912, + invention: 'Turing Machine' + }, + { + name: { + firstname: 'Graham', + lastname: 'Bell' + }, + born: 1847, + invention: 'telephone' + }, + { + name: { + firstname: 'Ada', + lastname: 'Lovelace' + }, + born: 1815, + invention: 'computer programming' + } +]) +``` + +Run the following `findOne()` operation to retrieve a single document from the collection: + +```js +db.scientists.findOne({ invention: 'Turing Machine' }) +``` + +## Retrieve all documents in a collection + +The `find()` command is used for retrieving all the documents in a collection. + +```js +db.collection.find() +``` + +Run `db.scientists.find()` to see the complete list of documents in the collection. + +### Retrieve documents based on a specific query + +Using the `find()` command, you can also filter a collection for only the documents that match the provided query. +For example, find the document with the field `born` set as 1857. + +```js +db.scientists.find({ born: 1857 }) +``` + +### Retrieve documents using operator queries + +The operator syntax allows users to query and retrieve a document. +There are several operator methods that you can use, such as `$gt` or `$lt`. +For example, to find the list of scientists born after the 1900s, we'll need the `$gt` operator: + +```js +db.scientists.find({ born: { $gt: 1900 } }) +``` + +Here is a list of the most commonly used operators. + +`$gt`: selects records that are greater than a specific value + +`$lt`: selects records that are less than a specific value + +`$gte`: selects records greater or equal to a specific value + +`$lte`: selects records less than or equal to a specific value + +`$in`: selects any record that contains any of the items present in a defined array + +`$nin`: selects any record that does not contain any of the items in a defined array + +`$ne`: selects records that are not equal to a specific value + +`$eq`: select records that are equal to a specific value + +### Retrieve documents containing a specific value in an array + +Insert the following documents into an `employees` collection using this command: + +```js +db.employees.insertMany([ + { + name: { + first: 'Earl', + last: 'Thomas' + }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + name: { + first: 'Sam', + last: 'Johnson' + }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + name: { + first: 'Clarke', + last: 'Dane' + }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +]) +``` + +To retrieve all documents with a specific array field and value (`catalog: "printer"`), run the following command: + +```js +db.employees.find({ catalog: 'printer' }) +``` + +The response displays all the retrieved documents: + +```json5 +[ + { + _id: ObjectId("636b39f80466c61a229bbf9b"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("636b3b0e0466c61a229bbf9d"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +### Retrieve documents in an array using dot notation + +To retrieve all documents containing a specific value in an array, use dot notation to reference its position in the `employees` collection. +The following command retrieves all documents containing `"blender"` in the third field of an array: + +```js +db.employees.find({ 'catalog.2': 'blender' }) +``` + +The document that matches the array query is displayed in the response: + +```json5 +[ + { + _id: ObjectId("636b3b0e0466c61a229bbf9c"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + } +] +``` + +### Query on an embedded or nested document + +To query on an embedded document, use dot notation to specify the fields. +The following command queries on the embedded document in the`employees` collection: + +```js +db.employees.find({ 'name.first': 'Clarke' }) +``` diff --git a/website/versioned_docs/version-v1.14/basic-operations/update.md b/website/versioned_docs/version-v1.14/basic-operations/update.md new file mode 100644 index 000000000000..0030e1e69053 --- /dev/null +++ b/website/versioned_docs/version-v1.14/basic-operations/update.md @@ -0,0 +1,205 @@ +--- +sidebar_position: 4 +--- + +# Update operation + +The update operation modifies a document record in a collection, based on a given query parameter and update. +FerretDB supports update operators, such as `$set` and `$setOnInsert` to update documents in a record. + +At present, FerretDB currently supports the following update operators: + +| Operator name | Description | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `$set` | Assigns the value for an updated field to the document. | +| `$setOnInsert` | Specifies the value of a field when an update operation results in the addition of a document. However, there is no effect when it modifies an existing document. | +| `$unset` | Removes a specific field from a document. | +| `$pop` | In an array, this operator removes the first or last item. | + +## Update a single document + +Use the `updateOne()` method to update a single document in a collection. +This operation filters a collection using a query parameter, and updates given fields within that document. + +```js +db.collection.updateOne({}, {$set: {}}) +``` + +First, populate the database with a collection containing a list of documents. + +```js +db.scientists.insertMany([ + { + firstname: 'Thomas', + lastname: 'Edison', + born: 1847, + invention: 'LightBulb', + nobel: true + }, + { + firstname: 'Graham', + lastname: 'Bell', + born: 1847, + invention: 'telephone', + nobel: false + }, + { + firstname: 'Nikola', + lastname: 'Tesla', + born: 1856, + invention: 'Tesla coil', + nobel: false + }, + { + firstname: 'Ada', + lastname: 'Lovelace', + born: 1815, + invention: 'Computer programming', + nobel: false + } +]) +``` + +Using the document record in the collection, update the document where `firstname` is "Graham", and set it as "Alexander Graham". +The `updateOne()` operation will only affect the first document that's retrieved in the collection. + +```js +db.scientists.updateOne( + { + firstname: 'Graham' + }, + { + $set: { + firstname: 'Alexander Graham' + } + } +) +``` + +## Replace a document + +Besides updating a document, you can replace it completely using the `replaceOne()` method. + +```js +db.scientists.replaceOne( + { + lastname: 'Bell' + }, + { + lastname: 'Einstein', + firstname: 'Albert', + born: 1879, + invention: 'Photoelectric effect', + nobel: true + } +) +``` + +## Update many documents + +Using the `updateMany()` command, you can modify many documents at once. +In the example below, where `nobel` is set as false, update and set to true. + +```js +db.scientists.updateMany({ nobel: false }, { $set: { nobel: true } }) +``` + +This operation updates all the documents where the field `nobel` was previously false. + +## Update an array element + +The following update example uses the `employees` collection. +To populate the collection, run the following in your terminal: + +```js +db.employees.insertMany([ + { + name: { + first: 'Earl', + last: 'Thomas' + }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + name: { + first: 'Sam', + last: 'Johnson' + }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + name: { + first: 'Clarke', + last: 'Dane' + }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +]) +``` + +The following command will query and update the `catalog` array in the `employee` collection using dot notation. +The command will query the second field of the array in every document for `"pencil"`, and when there is a match, updates the first element of the array. + +```js +db.employees.updateMany( + { + 'catalog.1': 'pencils' + }, + { + $set: { + 'catalog.0': 'ruler' + } + } +) +``` + +The response from the command: + +```js +{ + acknowledged: true, + insertedId: null, + matchedCount: 1, + modifiedCount: 1, + upsertedCount: 0 +} +``` + +## Update an embedded document + +To update an embedded document, use dot notation to specify the fields to modify. +The following operation updates any embedded document that matches the specified query in the `employees` collection. + +```js +db.employees.updateMany( + { + 'name.first': 'Clarke' + }, + { + $set: { + 'name.last': 'Elliot' + } + } +) +``` + +The following response from the command shows that a single document matching the query was updated: + +```js +{ + acknowledged: true, + insertedId: null, + matchedCount: 1, + modifiedCount: 1, + upsertedCount: 0 +} +``` diff --git a/website/versioned_docs/version-v1.14/configuration/_category_.yml b/website/versioned_docs/version-v1.14/configuration/_category_.yml new file mode 100644 index 000000000000..2524e7b4b4e1 --- /dev/null +++ b/website/versioned_docs/version-v1.14/configuration/_category_.yml @@ -0,0 +1,10 @@ +--- +label: Configuration +position: 10 +link: + type: generated-index + slug: /configuration/ + description: > + This configuration section provides guidance on setting up and customizing + the FerretDB environment through various flags, variables, and operation + modes diff --git a/website/versioned_docs/version-v1.14/configuration/flags.md b/website/versioned_docs/version-v1.14/configuration/flags.md new file mode 100644 index 000000000000..aaaca18df10d --- /dev/null +++ b/website/versioned_docs/version-v1.14/configuration/flags.md @@ -0,0 +1,114 @@ +--- +sidebar_position: 1 +--- + +# Configuration flags + +FerretDB provides numerous configuration flags you can customize to suit your needs and environment. +You can always see the complete list by using `--help` flag. +To make user experience cloud native, every flag has its environment variable equivalent. +There is no configuration file. + +:::info +Some default values are overridden in [our Docker image](../quickstart-guide/docker.md). +::: + + + + + + + +## General + +| Flag | Description | Environment Variable | Default Value | +| -------------- | ----------------------------------------------------------------- | -------------------- | ------------------------------ | +| `-h`, `--help` | Show context-sensitive help | | false | +| `--version` | Print version to stdout and exit | | false | +| `--handler` | Backend handler | `FERRETDB_HANDLER` | `pg` (PostgreSQL) | +| `--mode` | [Operation mode](operation-modes.md) | `FERRETDB_MODE` | `normal` | +| `--state-dir` | Path to the FerretDB state directory
(set to `-` to disable) | `FERRETDB_STATE_DIR` | `.`
(`/state` for Docker) | + +## Interfaces + +| Flag | Description | Environment Variable | Default Value | +| ------------------------ | ------------------------------------------------------------------------------------- | ------------------------------- | -------------------------------------------- | +| `--listen-addr` | Listen TCP address | `FERRETDB_LISTEN_ADDR` | `127.0.0.1:27017`
(`:27017` for Docker) | +| `--listen-unix` | Listen Unix domain socket path | `FERRETDB_LISTEN_UNIX` | | +| `--listen-tls` | Listen TLS address (see [here](../security/tls-connections.md)) | `FERRETDB_LISTEN_TLS` | | +| `--listen-tls-cert-file` | TLS cert file path | `FERRETDB_LISTEN_TLS_CERT_FILE` | | +| `--listen-tls-key-file` | TLS key file path | `FERRETDB_LISTEN_TLS_KEY_FILE` | | +| `--listen-tls-ca-file` | TLS CA file path | `FERRETDB_LISTEN_TLS_CA_FILE` | | +| `--proxy-addr` | Proxy address | `FERRETDB_PROXY_ADDR` | | +| `--proxy-tls-cert-file` | Proxy TLS cert file path | `FERRETDB_PROXY_TLS_CERT_FILE` | | +| `--proxy-tls-key-file` | Proxy TLS key file path | `FERRETDB_PROXY_TLS_KEY_FILE` | | +| `--proxy-tls-ca-file` | Proxy TLS CA file path | `FERRETDB_PROXY_TLS_CA_FILE` | | +| `--debug-addr` | Listen address for HTTP handlers for metrics, pprof, etc
(set to `-` to disable) | `FERRETDB_DEBUG_ADDR` | `127.0.0.1:8088`
(`:8088` for Docker) | + +## Backend handlers + + + +### PostgreSQL + +[PostgreSQL backend](../understanding-ferretdb.md#postgresql) can be enabled by +`--handler=pg` flag or `FERRETDB_HANDLER=pg` environment variable. + +| Flag | Description | Environment Variable | Default Value | +| ------------------ | ------------------------------- | ------------------------- | ------------------------------------ | +| `--postgresql-url` | PostgreSQL URL for 'pg' handler | `FERRETDB_POSTGRESQL_URL` | `postgres://127.0.0.1:5432/ferretdb` | + +FerretDB uses [pgx v5](https://github.com/jackc/pgx) library for connecting to PostgreSQL. +Supported URL parameters are documented there: + +- https://pkg.go.dev/github.com/jackc/pgx/v5/pgconn#ParseConfig +- https://pkg.go.dev/github.com/jackc/pgx/v5#ParseConfig +- https://pkg.go.dev/github.com/jackc/pgx/v5/pgxpool#ParseConfig + +Additionally: + +- `pool_max_conns` parameter is set to 50 if it is unset in the URL; +- `application_name` is always set to "FerretDB"; +- `timezone` is always set to "UTC". + +### SQLite + +[SQLite backend](../understanding-ferretdb.md#sqlite) can be enabled by +`--handler=sqlite` flag or `FERRETDB_HANDLER=sqlite` environment variable. + +| Flag | Description | Environment Variable | Default Value | +| -------------- | ------------------------------------------- | --------------------- | ------------------------------------------------- | +| `--sqlite-url` | SQLite URI (directory) for 'sqlite' handler | `FERRETDB_SQLITE_URL` | `file:data/` `.`
(`file:/state/` for Docker) | + +FerretDB uses [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) library for accessing SQLite database files. +Supported URL parameters are documented there: + +- https://www.sqlite.org/uri.html +- https://pkg.go.dev/modernc.org/sqlite#Driver.Open +- https://www.sqlite.org/pragma.html + +Additionally: + +- `_pragma=auto_vacuum(none)` parameter is set if that PRAGMA is not present; +- `_pragma=busy_timeout(10000)` parameter is set if that PRAGMA is not present; +- `_pragma=journal_mode(wal)` parameter is set if that PRAGMA is not present. + +One difference is that URI should point to the existing directory (with absolute or relative path), not to a single database file. +That allows FerretDB to work with multiple databases. + +In-memory SQLite databases are fully supported. +In that case, the URI should still point to the existing directory (that will be unused). +For example: `file:./?mode=memory`. + +## Miscellaneous + +| Flag | Description | Environment Variable | Default Value | +| --------------------- | ------------------------------------------------- | ----------------------- | ------------- | +| `--log-level` | Log level: 'debug', 'info', 'warn', 'error' | `FERRETDB_LOG_LEVEL` | `info` | +| `--[no-]log-uuid` | Add instance UUID to all log messages | `FERRETDB_LOG_UUID` | | +| `--[no-]metrics-uuid` | Add instance UUID to all metrics | `FERRETDB_METRICS_UUID` | | +| `--telemetry` | Enable or disable [basic telemetry](telemetry.md) | `FERRETDB_TELEMETRY` | `undecided` | + + + + diff --git a/website/versioned_docs/version-v1.14/configuration/observability.md b/website/versioned_docs/version-v1.14/configuration/observability.md new file mode 100644 index 000000000000..aefe006758db --- /dev/null +++ b/website/versioned_docs/version-v1.14/configuration/observability.md @@ -0,0 +1,45 @@ +--- +sidebar_position: 3 +description: Observability +--- + +# Observability + +## Logging + +The log level and format can be adjusted by [configuration flags](flags.md#miscellaneous). + +Please note that the structured log format is not stable yet; field names and formatting of values might change in minor releases. + +### Docker logs + +If Docker was launched with [our quick local setup with Docker Compose](../quickstart-guide/docker.md#setup-with-docker-compose), +the following command can be used to fetch the logs. + +```sh +docker compose logs ferretdb +``` + +Otherwise, you can check a list of running Docker containers with `docker ps` +and get logs with `docker logs`: + +```sh +$ docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +13db4c8800d3 postgres "docker-entrypoint.s…" About a minute ago Up 59 seconds 5432/tcp my-postgres +44fe6f4c3527 ghcr.io/ferretdb/ferretdb "/ferretdb" About a minute ago Up 59 seconds 8080/tcp, 27018/tcp, 0.0.0.0:27017->27017/tcp my-ferretdb + +$ docker logs my-ferretdb +``` + +### Binary executable logs + +FerretDB writes logs to the standard error (`stderr`) stream. + +## Metrics + +FerretDB exposes metrics in Prometheus format on the debug handler on `http://127.0.0.1:8088/debug/metrics` by default. +There is no need to use an external exporter. +The host and port can be changed with [`--debug-addr` flag](flags.md#interfaces). + +Please note that the set of metrics is not stable yet; metric and label names and formatting of values might change in minor releases. diff --git a/website/versioned_docs/version-v1.14/configuration/operation-modes.md b/website/versioned_docs/version-v1.14/configuration/operation-modes.md new file mode 100644 index 000000000000..7d3e5c587044 --- /dev/null +++ b/website/versioned_docs/version-v1.14/configuration/operation-modes.md @@ -0,0 +1,49 @@ +--- +sidebar_position: 2 +slug: /configuration/operation-modes/ # referenced in README.md +--- + +# Operation modes + +To simplify the development and debugging of FerretDB, we support different operation modes. +Operation modes specify how FerretDB handles incoming requests. +They are useful for testing, debugging, or bug reporting. + +You can specify modes by using the `--mode` flag or `FERRETDB_MODE` variable, +which accept following types of values: `normal`, `proxy`, `diff-normal`, `diff-proxy`. + +By default FerretDB always run on `normal` mode, which means that all client requests +are processed only by FerretDB and returned to the client. + +## Proxy + +Proxy is another MongoDB-compatible database, accessible from the machine. +You can specify its connection URL with `--proxy-addr` flag or with the `FERRETDB_PROXY_ADDR` variable. + +To forward all requests to proxy and return them to the client, use `proxy` operation mode. + +## Diff modes + +Diff modes (`diff-normal`, `diff-proxy`) forward requests to both databases, and log the difference between them. + +The `diff-normal` afterwards returns the response from FerretDB and `diff-proxy` - from the specified proxy handler. + +Example diff output: + +```diff +Header diff: +--- res header ++++ proxy header +@@ -1 +1 @@ +-length: 63, id: 14, response_to: 24, opcode: OP_MSG ++length: 64, id: 229, response_to: 24, opcode: OP_MSG + +Body diff: +--- res body ++++ proxy body +@@ -10,3 +10,3 @@ + ], +- "you": "127.0.0.1:57079", ++ "you": "172.19.0.1:59824", + "ok": { +``` diff --git a/website/versioned_docs/version-v1.14/contributing/_category_.yml b/website/versioned_docs/version-v1.14/contributing/_category_.yml new file mode 100644 index 000000000000..1fd6b7a57f8b --- /dev/null +++ b/website/versioned_docs/version-v1.14/contributing/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Contributing to FerretDB +position: 15 +link: + type: generated-index + slug: /contributing/ + description: > + Follow our guide on how to contribute to FerretDB diff --git a/website/versioned_docs/version-v1.14/contributing/index.md b/website/versioned_docs/version-v1.14/contributing/index.md new file mode 100644 index 000000000000..b405171cc58c --- /dev/null +++ b/website/versioned_docs/version-v1.14/contributing/index.md @@ -0,0 +1,48 @@ +--- +sidebar_position: 1 +slug: /how-to-contribute/ +--- + +# How to contribute to FerretDB + +FerretDB is an open source project and everyone – developers and non-developers – is welcome to contribute. +If you're interested in contributing to FerretDB projects, this documentation will help you get started. + +Here are some of the current FerretDB projects that you can fork and contribute to: + +- [FerretDB](https://github.com/FerretDB/FerretDB): This is the main repository of FerretDB. +- [dance](https://github.com/FerretDB/dance): This repository contains the FerretDB integration testing tool. +- [github-actions](https://github.com/FerretDB/github-actions): This repository houses our shared GitHub Actions for FerretDB, dance, and other repositories. + +For those taking their first steps in contributing to an open source project. +Please take a look at this post on [how to contribute to open source software](https://blog.ferretdb.io/how-to-contribute-to-open-source-2022/). + +## Get started + +You don't have to be a developer to contribute to FerretDB projects, you can even get started by helping us improve this documentation. +If you have any questions or suggestions on how we can improve, kindly join our [community](/#community). +We appreciate your feedback. + +## Contributing to this documentation + +If you find anything confusing or missing in the documentation, click the "Edit this page" link at the bottom of almost every page in the documentation. +More information on contributing to the documentation can be found [here](https://github.com/FerretDB/FerretDB/blob/main/CONTRIBUTING.md#contributing-documentation). + +## Contributing to the FerretDB repository + +- To contribute to this [FerretDB project](https://github.com/FerretDB/FerretDB/), please read the [CONTRIBUTING.md](https://github.com/FerretDB/FerretDB/blob/main/CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](https://github.com/FerretDB/FerretDB/blob/main/CODE_OF_CONDUCT.md) guideline to know more. +- Is everything working as it should? + If not, please let us know by [creating an issue](https://github.com/FerretDB/FerretDB/issues/new/choose). + You can create issues for bugs, documentation, features, or enhancements. +- You can identify issues you would like to work on by looking at the [open issues](https://github.com/FerretDB/FerretDB/issues) for this repository. +- The most straightforward way to start contributing to this repository is to select issues that are labeled [good-first-issues](https://github.com/FerretDB/FerretDB/contribute) + +## Contributing to dance + +- To start contributing to the [dance repository](https://github.com/FerretDB/dance) for integration testing, follow the guidelines in the [CONTRIBUTING.md](https://github.com/FerretDB/dance/blob/main/CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](https://github.com/FerretDB/dance/blob/main/CODE_OF_CONDUCT.md) files. +- Looking for something to work on? + Check out the [open issues](https://github.com/FerretDB/dance/issues) for this repository. + +## Contributing to github-actions + +- To contribute to our [github-actions repository](https://github.com/FerretDB/github-actions/), please go through the instructions in the [CONTRIBUTING.md](https://github.com/FerretDB/github-actions/blob/main/CONTRIBUTING.md) file. diff --git a/website/versioned_docs/version-v1.14/contributing/writing-guide.md b/website/versioned_docs/version-v1.14/contributing/writing-guide.md new file mode 100644 index 000000000000..de980c209aaf --- /dev/null +++ b/website/versioned_docs/version-v1.14/contributing/writing-guide.md @@ -0,0 +1,144 @@ +--- +sidebar_position: 99 +unlisted: true # linked from CONTRIBUTING.md +--- + +# Writing guide + +## Front matter + +The front matter represents the metadata for each page. +It is written at the top of each page and must be enclosed by `---` on both sides. + +Example: + +```yaml +--- +sidebar_position: 1 +description: How to write documentation +--- +``` + +Learn more about [front matter in Docusaurus](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-docs#markdown-front-matter). + +## Names and URLs + +Use `kebab-case-with-dashes` instead of `snake_case_with_underscores` or spaces +for file names, directory names, and slugs because URL paths typically use dashes. + +Ensure that the file name/URL path matches the title of the page. +For example, if the title of your page is "Getting Started", then the file name/URL path should also be "getting-started" to maintain consistency. +The `slug` field should be the same as the file name. +Only use a different `slug` field in some special cases, such as for backward compatibility with existing links. + +## Sidebar position + +Use the `sidebar_position` in the front matter to set the order of the pages in the sidebar. +Please ensure that the `sidebar_position` is unique for each page in that directory. +For example, if there are several pages in the folder "Getting Started", let `sidebar_position` equal "1", "2", "3", "4", and so on to avoid duplication. + +## Headers + +Use sentence case for headers: `### Some header with URL`, not `### Some Header With URL`. + +## Links + +Please use relative `.md` file paths for links. +It is required for [documentation versioning](https://docusaurus.io/docs/versioning#link-docs-by-file-paths). + +Examples: + +To link to a file in the same directory, use the file name. + +- `[file in the same directory](writing-guide.md)` + +To link to file in a different directory, specify the relative file path. + +- `[file in a different directory](../basic-operations/read.md)`. + +## Images + +Please store all images under `blog` or `docs` in the `static/img` folder. + +Also, you can collate images for a specific blog post inside a single folder. +For partner blog posts, store related images in the same folder, as `/img/blog/partner-name/image.png`. + +Otherwise, name the folder appropriately using the `YYYY-MM-DD` format, for example, a typical path for an image will be `/img/blog/2023-01-01/ferretdb-image.jpg`. + +### Alt text + +Please remember to add an alternate text for images. +The alt text should provide a description of the image for the user. +When you add a banner image, please use the title of the article as the alt text. + +### Image names + +Use of two or three descriptive words written in `kebab-case-with-dashes` as the names for the images. +For example, _ferretdb-queries.jpg_. + +### Image links + +Use Markdown syntax for images with descriptive alt texts and the path. +All assets (images, gifs, videos, etc.) relating to FerretDB documentation and blog are in the `static/img/` folder. +Rather than use relative paths, we strongly suggest the following approach, since our content engine renders all images directly from the `img` folder. + +`![FerretDB logo](/img/logo-dark.png)`. + +## Code blocks + +Always specify the language in Markdown code blocks. + +For MongoDB shell commands, use `js` language. +Our tooling will automatically reformat those blocks. + +```js +db.league.find({ club: 'PSG' }) +``` + +For MongoDB shell results, use `json5` language and copy&paste the output as-is, +with unquoted field names, single quotes for strings, without trailing commas, etc. +Our tooling will not reformat those blocks. + +```json5 +[ + { + _id: ObjectId("63109e9251bcc5e0155db0c2"), + club: 'PSG', + points: 30, + average_age: 30, + discipline: { red: 5, yellow: 30 }, + qualified: false + } +] +``` + +Use `sql` for SQL queries. +Use `text` for the `psql` output and in other cases. + +```sql +SELECT _jsonb FROM "test"."_ferretdb_database_metadata" WHERE ((_jsonb->'_id')::jsonb = '"customers"'); +``` + +```text + _jsonb ---------------------------------------------------------------------------------------------------------------------------------------------- + {"$s": {"p": {"_id": {"t": "string"}, "table": {"t": "string"}}, "$k": ["_id", "table"]}, "_id": "customers", "table": "customers_c09344de"} +``` + +```text +ferretdb=# \d test._ferretdb_settings + Table "test._ferretdb_settings" + Column | Type | Collation | Nullable | Default +----------+-------+-----------+----------+--------- + settings | jsonb | | | + +ferretdb=# SELECT settings FROM test._ferretdb_settings; + settings +-------------------------------------------------------------------------------------------------- + {"$k": ["collections"], "collections": {"$k": ["groceries"], "groceries": "groceries_6a5f9564"}} +(1 row) +``` + +## Terminologies + +To be sure that you're using the right descriptive term, please check our [glossary page](../reference/glossary.md) for relevant terms and terminologies about FerretDB. +If the word is not present in the glossary page, please feel free to ask on Slack or in the blog post issue. diff --git a/website/versioned_docs/version-v1.14/diff.md b/website/versioned_docs/version-v1.14/diff.md new file mode 100644 index 000000000000..a19fdd0faba3 --- /dev/null +++ b/website/versioned_docs/version-v1.14/diff.md @@ -0,0 +1,32 @@ +--- +sidebar_position: 11 +slug: /diff/ # referenced in README.md and beacon +--- + +# Known differences + + + +1. FerretDB uses the same protocol error names and codes, but the exact error messages may be different in some cases. +2. FerretDB does not support NUL (`\0`) characters in strings. +3. FerretDB does not support nested arrays. +4. FerretDB converts `-0` (negative zero) to `0` (positive zero). +5. Document restrictions: + - document keys must not contain `.` sign; + - document keys must not start with `$` sign; + - document fields of double type must not contain `Infinity`, `-Infinity`, or `NaN` values. +6. When insert command is called, insert documents must not have duplicate keys. +7. Update command restrictions: + - update operations producing `Infinity`, `-Infinity`, or `NaN` are not supported. +8. Database and collection names restrictions: + - name cannot start with the reserved prefix `_ferretdb_`; + - database name must not include non-latin letters; + - collection name must be valid UTF-8 characters; +9. FerretDB offers the same validation rules for the `scale` parameter in both the `collStats` and `dbStats` commands. + If an invalid `scale` value is provided in the `dbStats` command, the same error codes will be triggered as with the `collStats` command. + +If you encounter some other difference in behavior, +please [join our community](/#community) to report a problem. diff --git a/website/versioned_docs/version-v1.14/indexes.md b/website/versioned_docs/version-v1.14/indexes.md new file mode 100644 index 000000000000..37f5e2e170c4 --- /dev/null +++ b/website/versioned_docs/version-v1.14/indexes.md @@ -0,0 +1,140 @@ +--- +sidebar_position: 8 +--- + +# Indexes + +Indexes are essential in improving query performance by enabling fast retrieval of relevant documents when querying large collections. + +Indexes in FerretDB are created based on a specific field(s) within documents. +Creating an index involves having a data structure that maps the values in the indexed fields to the locations of the related documents, making it possible to retrieve documents more quickly based on those fields. + +## How to create indexes + +Use the `createIndexes()` command to create an index on a collection. +You can use the `createIndex()` method to call the `createIndexes()` command. + +The `createIndexes()` command takes two arguments: a document containing the index key (fields to index and direction - either ascending or descending), and an optional document specifying the index options. + +You can create single field indexes or compound indexes. + +### Single field indexes + +Suppose a `products` collection contains the following documents: + +```json5 +{ _id: 1, name: "iPhone 12", category: "smartphone", price: 799 } +{ _id: 2, name: "iPad Pro", category: "tablet", price: 999 } +{ _id: 3, name: "Galaxy S21", category: "smartphone", price: 699 } +{ _id: 4, name: "MacBook Pro", category: "laptop", price: 1299 } +``` + +Here's an example of the `createIndex` method to create an index on the `price` field of a `products` collection: + +```js +db.products.createIndex({ price: 1 }) +``` + +This creates an ascending index on the `price` field. + +:::note +`1` specifies the index direction for ascending order. +If it's `-1`, it specifies a descending order direction for the index. +::: + +### Compound indexes + +For compound indexes, you can create an index key combining multiple fields together as a key. +Below is an example of a compound index that uses `price` and `category` fields +from the `products` collection as the index key: + +```js +db.products.createIndex({ price: 1, category: 1 }) +``` + +### Unique indexes + +You can create unique indexes to ensure that the indexed fields do not contain duplicate values. +To create a unique index, set the `unique` option as `true` when calling `createIndexes()` command. + +Below is an example of a unique index for the `name` field from the `products` collection: + +```js +db.products.createIndex({ name: 1 }, { unique: true }) +``` + +Unique indexes can be compound. +Here is an example of a unique index consisting +of the `category` and `name` fields from the `products` collection: + +```js +db.products.createIndex({ category: 1, name: 1 }, { unique: true }) +``` + +### Index creation details + +- If the `createIndexes()` command is called for a non-existent collection, it will create the collection and its given indexes. +- If the `createIndexes()` command is called for a non-existent field, an index for the field is created without creating or adding the field to an existing collection. +- If you attempt to create an index with the same name and key as an existing index, the system will not create a duplicate index. + Instead, it will simply return the name and key of the existing index, since duplicate indexes would be redundant and inefficient. +- Meanwhile, any attempt to call `createIndexes()` command for an existing index using the same name and different key, _or_ different name but the same key will return an error. + +## How to list indexes + +To display a collection's index details, use the `listIndexes()` command. +You can also use the `getIndexes()` method to call the `listIndexes()` command. + +To return the list of indexes in the `products` collection, use the following command: + +```js +db.products.getIndexes() +``` + +The returned indexes should look like this, showing the default index, single field index, and compound index. + +```js +{ + cursor: { + id: Long("0"), + ns: 'db.products', + firstBatch: [ + { v: 2, key: { _id: 1 }, name: '_id_' }, + { v: 2, key: { price: 1 }, name: 'price_1' }, + { + v: 2, + key: { price: 1, category: 1 }, + name: 'price_1_category_1' + } + ] + }, + ok: 1 +} +``` + +## How to drop indexes + +You can also drop all the indexes or a particular index in a specified collection, except the default index (`_id`). + +FerretDB supports the use of the `dropIndexes()` command. +You can also use the `dropIndex()` method to call the `dropIndexes()` command to a particular index from a collection. + +Using the returned indexes above, let's drop the index with the name `price_1`. + +```js +db.products.dropIndex('price_1') +``` + +Another way to perform this action is to use the same index document as the index you want to drop. +For the same example above, you can rewrite it as: + +```js +db.products.dropIndex({ price: 1 }) +``` + +Using the `dropIndexes()` command, specify the index as `"*"` to remove all indexes from the collection, except the `_id` index. + +```js +db.products.dropIndexes('*') +``` + +This will drop all the non-`_id` indexes from the collection. diff --git a/website/versioned_docs/version-v1.14/main.md b/website/versioned_docs/version-v1.14/main.md new file mode 100644 index 000000000000..c94611dc92ad --- /dev/null +++ b/website/versioned_docs/version-v1.14/main.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 1 +slug: / +description: This is the FerretDB documentation, containing all the details on FerretDB – the open-source MongoDB alternative that translates MongoDB wire protocol queries to SQL, with PostgreSQL or SQLite as the database engine. +--- + +# Introduction + +FerretDB is an open-source proxy that translates MongoDB wire protocol queries to SQL, +with PostgreSQL or SQLite as the database engine. + +Initially built as open-source software, MongoDB was a game-changer for many developers, +enabling them to build fast and robust applications. +Its ease of use and extensive documentation made it a top choice for many developers looking +for an open-source database. +However, all this changed when they switched to an SSPL license, +moving away from their open-source roots. + +In light of this, FerretDB was founded to become the true open-source alternative to MongoDB, +making it the go-to choice for most MongoDB users looking for an open-source alternative to MongoDB. +With FerretDB, users can run the same MongoDB protocol queries without needing to learn a new language or command. + +## Scope and current state + +FerretDB is compatible with MongoDB drivers and can be used as a direct replacement for MongoDB 5.0+. +We are constantly adding features to increase compatibility based on user feedback. + +See our [public roadmap](https://github.com/orgs/FerretDB/projects/2/views/1), +a list of [known differences with MongoDB](diff.md), +and [contributing guidelines](https://github.com/FerretDB/FerretDB/blob/main/CONTRIBUTING.md). + +## Community + +- Website and blog: https://www.ferretdb.com/. +- Twitter: [@ferret_db](https://twitter.com/ferret_db). +- Mastodon: [@ferretdb@techhub.social](https://techhub.social/@ferretdb). +- [Slack chat](https://join.slack.com/t/ferretdb/shared_invite/zt-zqe9hj8g-ZcMG3~5Cs5u9uuOPnZB8~A) for quick questions. +- [GitHub Discussions](https://github.com/FerretDB/FerretDB/discussions) for longer topics. +- [GitHub Issues](https://github.com/FerretDB/FerretDB/issues) for bugs and missing features. +- [Open Office Hours meeting](https://calendar.google.com/event?action=TEMPLATE&tmeid=NjNkdTkyN3VoNW5zdHRiaHZybXFtb2l1OWtfMjAyMTEyMTNUMTgwMDAwWiBjX24zN3RxdW9yZWlsOWIwMm0wNzQwMDA3MjQ0QGc&tmsrc=c_n37tquoreil9b02m0740007244%40group.calendar.google.com&scp=ALL) + every Monday at 18:00 UTC at [Google Meet](https://meet.google.com/mcb-arhw-qbq). + +If you want to contact FerretDB Inc., please use [this form](https://www.ferretdb.com/contact/). diff --git a/website/versioned_docs/version-v1.14/migration/_category_.yml b/website/versioned_docs/version-v1.14/migration/_category_.yml new file mode 100644 index 000000000000..d4668fd46751 --- /dev/null +++ b/website/versioned_docs/version-v1.14/migration/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Migrating to FerretDB +position: 9 +link: + type: generated-index + slug: /migration/ + description: > + This section details the procedures on how to migrate to FerretDB diff --git a/website/versioned_docs/version-v1.14/migration/migrating-from-mongodb.md b/website/versioned_docs/version-v1.14/migration/migrating-from-mongodb.md new file mode 100644 index 000000000000..1d95069f2311 --- /dev/null +++ b/website/versioned_docs/version-v1.14/migration/migrating-from-mongodb.md @@ -0,0 +1,66 @@ +--- +sidebar_position: 2 +--- + +# Migrating from MongoDB + +Before you begin this section of the migration process, go through the pre-migration process so as to ensure a successful migration from MongoDB to FerretDB: + +- [Pre-migration testing](premigration-testing.md) + +This guide will help you migrate your data from MongoDB – locally or online – to FerretDB. + +As an open-source MongoDB alternative, FerretDB is built to work with many MongoDB tools. +In that case, you can migrate your data using MongoDB native tools such as `mongodump`/`mongorestore` and `mongoexport`/`mongoimport`. + +Before you go forward with the migration, you need to have the following: + +- MongoDB connection URI +- FerretDB connection URI +- MongoDB native tools + +## Backup your MongoDB data + +To backup your MongoDB instance using `mongodump` or `mongoexport`, you'll need to set the connection string to your MongoDB instance (e.g. `"mongodb://127.0.0.1:27017"`) to run the following command: + +```sh +mongodump --uri="mongodb://:@:" +``` + +The `mongodump` command will create a dump of all the data in the instance, consisting of BSON files of all the collections. +Also, you can migrate a specific database (e.g. `--db=test`) or collection (e.g. `--collection=supply`) using their respective parameters after the `--uri` connection string. + +:::caution +If you include the database in your connection string, there's no need to specify a database name for the backup or restore process. +::: + +```sh +mongoexport --uri="mongodb://:@:" --db= --collection= --out=.json +``` + +On the other hand, `mongoexport` does not provide a direct way to export all the collections at once, like `mongodump` does. + +Instead, you need to set the connection string to connect with your preferred database and then run the command together with the parameters for the collection (`--collection=myCollection`) and the directory you want to export to (e.g. `--out=collection-name.json`). + +## Restore your data to FerretDB + +To restore or import your backed-up data to FerretDB, set the connection string to your FerretDB instance and use `mongorestore` and `mongoimport`. + +Run the following command in your terminal, from your `dump` folder: + +```sh +mongorestore --uri="mongodb://:@:/?authMechanism=PLAIN" +``` + +With this command, you can restore all the data in `dump` into your FerretDB instance. +You can also specify the database and collection (`dump//`) you want to restore from the `dump` folder, according to your preferences. + +To import your database using `mongoimport`, run the command from the terminal directory where you exported your data: + +````sh + +```sh +mongoimport--uri="mongodb://:@:/?authMechanism=PLAIN" --db= --collection= --file=.json +```` + +The command will import the specified collection you exported from your MongoDB instance to FerretDB. diff --git a/website/versioned_docs/version-v1.14/migration/premigration-testing.md b/website/versioned_docs/version-v1.14/migration/premigration-testing.md new file mode 100644 index 000000000000..fce33ba77e90 --- /dev/null +++ b/website/versioned_docs/version-v1.14/migration/premigration-testing.md @@ -0,0 +1,233 @@ +--- +sidebar_position: 1 +--- + +# Pre-migration testing + +To ensure a smooth and successful migration from MongoDB, we offer several methods through which you can test your application with FerretDB. + +## Operation modes + +We offer multiple operation modes which help facilitate the testing of your application by enabling FerretDB to act as a proxy. +For more details, refer to the [operation modes](../configuration/operation-modes.md). + +### Manual and automated testing with `diff-normal` mode + +For details on how to install FerretDB, refer to the [quickstart guide](../../quickstart-guide/). + +You can manually test your application or use integration tests, among other methods. +Afterward, you can inspect the differential output for errors or inconsistencies between responses that require your attention. + +As an example, let us say that your application performs some complex query and you'd like to test it in `diff-normal` mode. +You would do the following: + +1. Start FerretDB in `diff-normal` mode. + + This can be achieved by setting the `--mode` [flag](../configuration/flags.md) or `FERRETDB_MODE` environment variable to `diff-normal`. + By default, FerretDB starts in normal mode (`--mode=normal`/`FERRETDB_MODE=normal`). + For more details, see [operation modes](../configuration/operation-modes.md). + + Ensure to specify `--listen-addr` and `--proxy-addr` flags or set the `FERRETDB_LISTEN_ADDR` and `FERRETDB_PROXY_ADDR` environment variables. + Specify the address of your MongoDB instance for `--proxy-addr` flag or `FERRETDB_PROXY_ADDR` environment variable. + [See docs for more details](https://docs.ferretdb.io/configuration/flags/#interfaces). For example: + + ```sh + ferretdb --mode=diff-normal \ + --proxy-addr= \ + --listen-addr= \ + --postgresql-url= + ``` + + The `--listen-addr` flag or the `FERRERDB_LISTEN_ADDR` environment variable is set to `127.0.0.1:27017` by default. + +2. Run `mongosh` to connect to the `--listen-addr` and then insert some documents. +3. Run a query to fetch the first post from each author sorted by date and author. + + Please note that due to running in `diff-normal` mode, any error returned from FerretDB will be transmitted to the client, allowing us to promptly identify the issue. + In the majority of cases, this does not necessitate additional scrutiny of the diff output. + Nevertheless, if FerretDB does not handle the error, additional inspection becomes necessary. + + ```sh + # run mongosh + $ mongosh + ``` + + ```js + // insert some documents + db.posts.insertMany([ + { + title: 'title A', + body: 'some content', + author: 'Bob', + date: ISODate('2023-08-29T10:33:23.134Z') + }, + { + title: 'another title', + body: 'some content', + author: 'Bob', + date: ISODate('2023-08-28T10:33:23.134Z') + }, + { + title: 'title B', + body: 'some content', + author: 'Alice', + date: ISODate('2023-08-20T10:33:23.134Z') + }, + { + title: 'some other title', + body: 'some content', + author: 'Alice', + date: ISODate('2023-08-21T10:33:23.134Z') + } + ]) + + // run the query + db.posts.aggregate([ + { $sort: { date: 1, author: 1 } }, + { + $group: { + _id: '$author', + firstPost: { $first: '$date' } + } + } + ]) + // the below error is returned to the client: + // MongoServerError: $group accumulator "$first" is not implemented yet + ``` + +### Manual and automated testing with `diff-proxy` mode + +Continuing with the same example above, we can further examine the diff output while in `diff-proxy` mode. + +1. Run FerretDB in `diff-proxy` mode. + This can again be achieved by using the `--mode` [flag](../configuration/flags.md) or by setting the `FERRETDB_MODE` environment variable to `diff-proxy`. +2. Follow the same instructions as the one for `diff-normal` above to run FerretDB in `diff-proxy` mode and re-run the query. + + ```js + db.posts.aggregate([ + { $sort: { date: 1, author: 1 } }, + { + $group: { + _id: '$author', + firstPost: { $first: '$date' } + } + } + ]) + // the query was handled by MongoDB, so the following documents are returned: + // { _id: 'Alice', firstPost: ISODate("2023-08-20T10:33:23.134Z") } + // { _id: 'Bob', firstPost: ISODate("2023-08-28T10:33:23.134Z") } + ``` + +In the diff output below, however, we have discovered that the query cannot be serviced by our application because the `$first` accumulator operator is not implemented in FerretDB. + +```diff +2023-08-29T13:25:09.048+0200 WARN // 127.0.0.1:33522 -> 127.0.0.1:27017 clientconn/conn.go:360 Header diff: +--- res header ++++ proxy header +@@ -1 +1 @@ +-length: 140, id: 2, response_to: 156, opcode: OP_MSG ++length: 181, id: 360, response_to: 156, opcode: OP_MSG + +Body diff: +--- res body ++++ proxy body +@@ -7,13 +7,41 @@ + "$k": [ +- "ok", +- "errmsg", +- "code", +- "codeName" ++ "cursor", ++ "ok" + ], ++ "cursor": { ++ "$k": [ ++ "firstBatch", ++ "id", ++ "ns" ++ ], ++ "firstBatch": [ ++ { ++ "$k": [ ++ "_id", ++ "firstPost" ++ ], ++ "_id": "Alice", ++ "firstPost": { ++ "$d": 1692527603134 ++ } ++ }, ++ { ++ "$k": [ ++ "_id", ++ "firstPost" ++ ], ++ "_id": "Bob", ++ "firstPost": { ++ "$d": 1693218803134 ++ } ++ } ++ ], ++ "id": { ++ "$l": "0" ++ }, ++ "ns": "test.posts" ++ }, + "ok": { +- "$f": 0 +- }, +- "errmsg": "$group accumulator \"$first\" is not implemented yet", +- "code": 238, +- "codeName": "NotImplemented" ++ "$f": 1 ++ } + }, +``` + +### Response metrics + +Metrics are captured and written to standard output (`stdout`) upon exiting in [Debug builds](https://pkg.go.dev/github.com/FerretDB/FerretDB/build/version#hdr-Debug_builds). +This is a useful way to quickly determine what commands are not implemented for the client requests sent by your application. +In the metrics provided below, we can observe that the `$first` accumulator operator was invoked 18 times within the aggregate command, and the `findAndModify` command was executed 6 times with a `fields` projection document. +Both of these operations resulted in `result="NotImplemented"`. +To address this issue, it's essential to carefully inspect any result that lacks an `ok` value. + +```text +# HELP ferretdb_client_requests_total Total number of requests. +# TYPE ferretdb_client_requests_total counter +ferretdb_client_requests_total{command="aggregate",opcode="OP_MSG"} 105 +ferretdb_client_requests_total{command="find",opcode="OP_MSG"} 398 +ferretdb_client_requests_total{command="findAndModify",opcode="OP_MSG"} 6 +ferretdb_client_requests_total{command="hello",opcode="OP_MSG"} 4 +ferretdb_client_requests_total{command="insert",opcode="OP_MSG"} 10 +ferretdb_client_requests_total{command="ismaster",opcode="OP_MSG"} 17 +ferretdb_client_requests_total{command="unknown",opcode="OP_QUERY"} 28 +ferretdb_client_requests_total{command="update",opcode="OP_MSG"} 59 +# HELP ferretdb_client_responses_total Total number of responses. +# TYPE ferretdb_client_responses_total counter +ferretdb_client_responses_total{argument="$first (accumulator)",command="aggregate",opcode="OP_MSG",result="NotImplemented"} 18 +ferretdb_client_responses_total{argument="fields",command="findAndModify",opcode="OP_MSG",result="NotImplemented"} 6 +ferretdb_client_responses_total{argument="unknown",command="aggregate",opcode="OP_MSG",result="ok"} 87 +ferretdb_client_responses_total{argument="unknown",command="find",opcode="OP_MSG",result="ok"} 398 +ferretdb_client_responses_total{argument="unknown",command="hello",opcode="OP_MSG",result="ok"} 4 +ferretdb_client_responses_total{argument="unknown",command="insert",opcode="OP_MSG",result="ok"} 10 +ferretdb_client_responses_total{argument="unknown",command="ismaster",opcode="OP_MSG",result="ok"} 17 +ferretdb_client_responses_total{argument="unknown",command="unknown",opcode="OP_REPLY",result="ok"} 28 +ferretdb_client_responses_total{argument="unknown",command="update",opcode="OP_MSG",result="ok"} 59 +``` + +### Other tools + +We also have a fork of the Amazon DocumentDB Compatibility Tool [here](https://github.com/FerretDB/amazon-documentdb-tools/tree/master/compat-tool). +The tool examines files to identify queries that use unsupported operators in FerretDB. +Please note that this tool is not highly accurate and may generate inaccurate reports, as it does not parse query syntax with contextual information about the originating command. +For example, an unsupported operator might appear within a `find` or `aggregate` command, which the tool does not differentiate. +Note that we also mark operators as unsupported if they are not supported in _all_ commands, which could result in false negatives. + +Running the tool to check FerretDB compatibility: + +```sh +# clone the repository and run the compat-tool +$ git clone https://github.com/FerretDB/amazon-documentdb-tools.git && cd amazon-documentdb-tools/compat-tool +$ python3 compat.py --directory=/path/to/myapp --version=FerretDB +``` diff --git a/website/versioned_docs/version-v1.14/operators/_category_.yml b/website/versioned_docs/version-v1.14/operators/_category_.yml new file mode 100644 index 000000000000..5dd8c8338976 --- /dev/null +++ b/website/versioned_docs/version-v1.14/operators/_category_.yml @@ -0,0 +1,9 @@ +--- +label: Operators +position: 5 +link: + type: generated-index + slug: /operators/ + description: > + The complete list of operators, including query operators, update operators, + aggregation operators, etc. diff --git a/website/versioned_docs/version-v1.14/operators/query/_category_.yml b/website/versioned_docs/version-v1.14/operators/query/_category_.yml new file mode 100644 index 000000000000..75be6a917b7a --- /dev/null +++ b/website/versioned_docs/version-v1.14/operators/query/_category_.yml @@ -0,0 +1,9 @@ +--- +label: Query Operators +position: 1 +link: + type: generated-index + slug: /query/ + description: > + The list of all different types of query operators available on FerretDB, + including comparison operators, logical operators, array operators, etc. diff --git a/website/versioned_docs/version-v1.14/operators/query/array-operators.md b/website/versioned_docs/version-v1.14/operators/query/array-operators.md new file mode 100644 index 000000000000..e4943f0e00a3 --- /dev/null +++ b/website/versioned_docs/version-v1.14/operators/query/array-operators.md @@ -0,0 +1,195 @@ +--- +sidebar_position: 3 +--- + +# Array query operators + +Array query operators allow you to search for specific elements within an array field in a document. + +| Operator | Description | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| [`$all`](#all) | Selects an array that contains all elements from a given query. | +| [`$elemMatch`](#elemmatch) | Matches a document that contains an array field with at least one element that matches all the specified query criteria | +| [`$size`](#size) | Matches an array with a specified number of elements | + +For the examples in this section, insert the following documents into the `team` collection: + +```js +db.team.insertMany([ + { + id: 1, + name: 'Jack Smith', + position: 'Manager', + skills: ['leadership', 'communication', 'project management'], + contact: { + email: 'john@example.com', + phone: '123-456-7890' + }, + active: true + }, + { + id: 2, + name: 'Jane Mark', + position: 'Software Developer', + skills: ['Java', 'Python', 'C++'], + contact: { + email: 'jane@example.com', + phone: '123-456-7891' + }, + active: false + }, + { + id: 3, + name: 'Bob Johnson', + position: 'Graphic Designer', + skills: ['Adobe Photoshop', 'Illustrator', 'InDesign'], + contact: { + email: 'bob@example.com', + phone: '123-456-7892' + }, + active: true + }, + { + id: 4, + name: 'Alice Williams', + position: 'Marketing Coordinator', + skills: ['communication', 'content creation', 'event planning'], + contact: { + email: 'alice@example.com', + phone: '123-456-7893' + }, + active: true + } +]) +``` + +## $all + +_Syntax_: `{ : { $all: [ , , ... ] } }` + +Use the `$all` operator when you want to select documents that contain every single element in a specified array. + +:::note +When using an `$all` operator, the order of the elements and array size does not matter, as long as the array contains all the elements in the query. +::: + +**Example:** Find all documents in the `team` collection where the `skills` field contains both `communication` and `content creation` as elements using the following query operation: + +```js +db.team.find({ + skills: { + $all: ['communication', 'content creation'] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a5bb4acf72d6203bb45bb5"), + id: 4, + name: 'Alice Williams', + position: 'Marketing Coordinator', + skills: ['communication', 'content creation', 'event planning'], + contact: { email: 'alice@example.com', phone: '123-456-7893' }, + active: true + } +] +``` + +## $elemMatch + +_Syntax_: `{ : { $elemMatch: { , , ... } } }` + +To select documents in a specified array field where one or more elements match all listed query conditions, use the `$elemMatch` operator. + +**Example:** Find documents in the `team` collection where the `skills` field is an array that contains the element "Java", and array does not contain the element `communication`. +Use the following query operation: + +```js +db.team.find({ + skills: { + $elemMatch: { + $eq: 'Java', + $nin: ['communication'] + } + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63aa247e69c82de72bd40b93"), + id: 2, + name: 'Jane Mark', + position: 'Software Developer', + skills: ['Java', 'Python', 'C++'], + contact: { email: 'jane@example.com', phone: '123-456-7891' }, + active: false + } +] +``` + +## $size + +_Syntax_: `{ : { $size: } }` + +The `$size` operator is ideal for selecting array fields containing a specified number of elements. + +**Example:** Select the documents in the `team` collection where the `skills` array contains only three elements. + +```js +db.team.find({ + skills: { + $size: 3 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63aa247e69c82de72bd40b92"), + id: 1, + name: 'Jack Smith', + position: 'Manager', + skills: ['leadership', 'communication', 'project management'], + contact: { email: 'john@example.com', phone: '123-456-7890' }, + active: true + }, + { + _id: ObjectId("63aa247e69c82de72bd40b93"), + id: 2, + name: 'Jane Mark', + position: 'Software Developer', + skills: ['Java', 'Python', 'C++'], + contact: { email: 'jane@example.com', phone: '123-456-7891' }, + active: false + }, + { + _id: ObjectId("63aa247e69c82de72bd40b94"), + id: 3, + name: 'Bob Johnson', + position: 'Graphic Designer', + skills: ['Adobe Photoshop', 'Illustrator', 'InDesign'], + contact: { email: 'bob@example.com', phone: '123-456-7892' }, + active: true + }, + { + _id: ObjectId("63aa247e69c82de72bd40b95"), + id: 4, + name: 'Alice Williams', + position: 'Marketing Coordinator', + skills: ['communication', 'content creation', 'event planning'], + contact: { email: 'alice@example.com', phone: '123-456-7893' }, + active: true + } +] +``` diff --git a/website/versioned_docs/version-v1.14/operators/query/bitwise-operators.md b/website/versioned_docs/version-v1.14/operators/query/bitwise-operators.md new file mode 100644 index 000000000000..14a01d1756f5 --- /dev/null +++ b/website/versioned_docs/version-v1.14/operators/query/bitwise-operators.md @@ -0,0 +1,159 @@ +--- +sidebar_position: 1 +--- + +# Bitwise query operators + +Bitwise query operators help to select documents by evaluating query conditions according to the location of bits. + +| Operator | Description | +| -------------------------------- | ---------------------------------------------------------- | +| [`$bitsAllClear`](#bitsallclear) | Selects documents with clear bit locations (0) | +| [`$bitsAllSet`](#bitsallset) | Selects documents with set bit locations (1) | +| [`$bitsAnyClear`](#bitsanyclear) | Selects documents with at least one clear bit location (0) | +| [`$bitsAnySet`](#bitsanyset) | Selects documents with at least one set bit location (1) | + +For the examples in this section, insert the following documents into the `numbers` collection: + +```js +db.numbers.insertMany([ + { _id: 1, value: 23, binaryValue: '10111' }, + { _id: 2, value: 56, binaryValue: '111000' }, + { _id: 3, value: 67, binaryValue: '1000011' }, + { _id: 4, value: 102, binaryValue: '1100110' }, + { _id: 5, value: 5, binaryValue: '101' } +]) +``` + +## $bitsAllClear + +_Syntax_: `{ : { $bitsAllClear: } }` + +Use the `$bitsAllClear` operator to select documents where the specified bitmask locations in the query are clear (0). + +:::tip +The bitmask can either be a numeric or BinData value. +A BinData value is a BSON type that represents a binary value. +The position of the bits is read from right to left with the rightmost position being `0`. +::: + +**Example:** The following query returns documents in which the `value` field has the second and third bit (position `1` and position `2`) from the right as clear (0). + +```js +db.numbers.find({ + value: { + $bitsAllClear: 6 + } +}) +``` + +The binary representation for `6` in this query is `110`. +The query can also be written to show the positions of the bits to be checked: + +```js +db.numbers.find({ + value: { + $bitsAllClear: [1, 2] + } +}) +``` + +The output: + +```json5 +[{ _id: 2, value: 56, binaryValue: '111000' }] +``` + +For the same query above, the bitmask can also be written as a BinData value: + +```js +db.numbers.find({ + value: { + $bitsAllClear: BinData(0, 'Bg==') + } +}) +``` + +## $bitsAllSet + +_Syntax_: `{ : { $bitsAllSet: } }` + +To select documents where the bitmask locations in a query are set (1), use the `$bitsAllSet` operator. + +**Example:** The following query returns all the documents with positions `1` and positions `2` as set (1): + +```js +db.numbers.find({ + value: { + $bitsAllSet: [1, 2] + } +}) +``` + +The output: + +```json5 +[ + { _id: 1, value: 23, binaryValue: '10111' }, + { _id: 4, value: 102, binaryValue: '1100110' } +] +``` + +See the [$bitsAllClear query operator](#bitsallclear) section for more usage examples. + +## $bitsAnyClear + +_Syntax_: `{ : { $bitsAnyClear: } }` + +Use the `$bitsAnyClear` operator to select documents where at least one of the bitmask locations in the query is clear (0). + +**Example:** The following query returns all the documents with positions `0` and positions `2` as clear (0): + +```js +db.numbers.find({ + value: { + $bitsAnyClear: [0, 2] + } +}) +``` + +The output: + +```json5 +[ + { _id: 2, value: 56, binaryValue: '111000' }, + { _id: 3, value: 67, binaryValue: '1000011' }, + { _id: 4, value: 102, binaryValue: '1100110' } +] +``` + +See the [$bitsAllClear query operator](#bitsallclear) section for more usage examples. + +## $bitsAnySet + +_Syntax_: `{ : { $bitsAnySet: } }` + +The `$bitsAnySet` operator selects documents where at least one of the bitmask locations in the query is set (1). + +**Example:** The following query returns all the documents with positions `0` and positions `2` as set (1): + +```js +db.numbers.find({ + value: { + $bitsAnySet: [0, 2] + } +}) +``` + +The output: + +```json5 +[ + { _id: 1, value: 23, binaryValue: '10111' }, + { _id: 3, value: 67, binaryValue: '1000011' }, + { _id: 4, value: 102, binaryValue: '1100110' }, + { _id: 5, value: 5, binaryValue: '101' } +] +``` + +See the [$bitsAllClear query operator](#bitsallclear) section for more usage examples. diff --git a/website/versioned_docs/version-v1.14/operators/query/comparison-operators.md b/website/versioned_docs/version-v1.14/operators/query/comparison-operators.md new file mode 100644 index 000000000000..e4033deffece --- /dev/null +++ b/website/versioned_docs/version-v1.14/operators/query/comparison-operators.md @@ -0,0 +1,383 @@ +--- +sidebar_position: 1 +--- + +# Comparison query operators + +Comparison query operators allow you to compare the elements in a document to a given query value. + +Go to the comparison query operators: + +| Operator | Description | +| -------------- | ------------------------------------------------------------------------- | +| [`$eq`](#eq) | Selects documents with elements that are equal to a given query value | +| [`$gt`](#gt) | Selects documents with elements that are greater than a given query value | +| [`$gte`](#gte) | Selects documents greater than or equal to specified query | +| [`$lt`](#lt) | Selects documents with elements that are less than a given query value | +| [`$lte`](#lte) | Selects documents with elements less than or equal to given query value | +| [`$in`](#in) | Selects documents that contain the elements in a given array query | +| [`$ne`](#ne) | Selects documents with elements that are not equal to given query value | +| [`$nin`](#nin) | Selects documents that do not contain the elements in a given array query | + +For the examples in this section, insert the following documents into the `employees` collection: + +```js +db.employees.insertMany([ + { + name: { + first: 'Earl', + last: 'Thomas' + }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + name: { + first: 'Sam', + last: 'Johnson' + }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + name: { + first: 'Clarke', + last: 'Dane' + }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +]) +``` + +## $eq + +_Syntax_: `{ : { $eq: } }` + +To select documents that exactly match a given query value, use the `$eq` operator. + +This operator can be used to match values of different types, including documents, array, embedded documents, etc. + +**Example:** The following operation queries the `employees` collection for all documents where the field `age` equals `21`. + +```js +db.employees.find({ + age: { + $eq: 21 + } +}) +``` + +The response returns a single document that matches the query: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +**Example:** To query values in an embedded document, use [dot notation](../../understanding-ferretdb.md#dot-notation). +The following operation queries the `employees` collection for documents that match the field `first` in the embedded document `name`. + +```js +db.employees.find({ + 'name.first': { + $eq: 'Earl' + } +}) +``` + +The response returns a single document that matches the query: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + } +] +``` + +## $gt + +_Syntax_: `{ : { $gt: } }` + +To identify documents containing elements that have a greater value than the specified one in the query, use the `$gt` operator. + +**Example:** Use the following operation to query for all the documents in the `employees` collection where the field `age` is greater than `21`. + +```js +db.employees.find({ + age: { + $gt: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + } +] +``` + +## $gte + +_Syntax_: `{ : { $gte: } }` + +Use the `$gte` to select document with elements that are greater than or equal to a specified value. + +**Example:** The following operation selects documents based on the specified query, where the field `age` is greater than or equal to `21`. + +```js +db.employees.find({ + age: { + $gte: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $lt + +_Syntax_: `{ : { $lt: } }` + +Contrary to the `$gt` operator, the `$lt` operator is ideal for selecting documents with elements that are of a lesser value than that of the specified query. + +**Example:** The following operation queries for documents where the field `age` is less than `25`. + +```js +db.employees.find({ + age: { + $lt: 25 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $lte + +_Syntax_: `{ : { $lte: } }` + +The `$lte` operator is the opposite of the `$gte` operator. +Use the `$lte` operator to select documents with elements that are less than or equal to the specified query value. + +**Example:** The following operation queries for documents where the field `age` is less than or equal to `21`. + +```js +db.employees.find({ + age: { + $lte: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $in + +_Syntax_: `{ : { $in: [, , ... ] } }` + +To select documents containing any of the listed elements in a specified array field, use the `$in` operator. + +**Example:** The following operation queries the `employees` collection for documents where the value of the field `age` is either `21` or `35`. + +```js +db.employees.find({ + age: { + $in: [21, 35] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $ne + +_Syntax_: `{ : { $ne: } }` + +Use the `$ne` operator to select all the documents with elements that are not equal to a given query. + +**Example:** The following operation queries the `employees` collection for documents where the field `age` is not equal to `21`. + +```js +db.employees.find({ + age: { + $ne: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + } +] +``` + +## $nin + +_Syntax_: `{ : { $nin: [ , ... ] } }` + +The `$nin` does exactly the opposite of the `$in` operator. +Use the `$nin` operator when selecting documents that do match or contain any of the elements listed in an array query. + +**Example:** The following operation queries the `employees` collection for documents where the value of the field `age` is not `21` or `35`. + +```js +db.employees.find({ + age: { + $nin: [21, 35] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + } +] +``` diff --git a/website/versioned_docs/version-v1.14/operators/query/element-operators.md b/website/versioned_docs/version-v1.14/operators/query/element-operators.md new file mode 100644 index 000000000000..c18d1f105a15 --- /dev/null +++ b/website/versioned_docs/version-v1.14/operators/query/element-operators.md @@ -0,0 +1,363 @@ +--- +sidebar_position: 4 +--- + +# Element query operators + +Element query operators return data based on the existence of a specified field or the data type of a particular value. + +| Operator | Description | +| -------------------- | ------------------------------------------------------------ | +| [`$exists`](#exists) | returns documents where a field exists or does not exist | +| [`$type`](#type) | matches document containing elements with the specified type | + +For the examples in this section, insert the following documents into the `electronics` collection: + +```js +db.electronics.insertMany([ + { + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [ + { + processor: 'Intel Core i7' + }, + { + memory: 16 + } + ] + }, + { + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [ + { + brand: 'Apple' + }, + { + model: 'iPhone 12' + } + ] + }, + { + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [ + { + brand: 'Samsung' + }, + { + model: 'Galaxy Tab S7' + } + ] + }, + { + product: 'keyboard', + price: 100, + stock: 20 + }, + { + product: 'mouse', + price: 50, + stock: 25, + discount: null, + specifications: [] + }, + { + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [ + { + size: 27 + }, + { + resolution: '4K' + } + ] + }, + { + product: 'printer', + price: 150, + stock: 35, + discount: false + }, + { + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [ + { + type: 'flatbed' + } + ] + } +]) +``` + +## $exists + +_Syntax_: `{ : { $exists: } }` + +To find out if a particular field exists in a document, use the `$exists` operator. + +:::tip +If the `` value is `true`, the query returns documents where the specified field exists, even if the value is `null` or an empty array. +If the `` value is `false`, the query returns documents where the specified field does not exist. +::: + +**Example:** Find documents in the `electronics` collection where the `specifications` field exists using the `$exists` operator: + +```js +db.electronics.find({ + specifications: { + $exists: true + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a32fc7cf72d6203bb45b8e"), + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [{ processor: 'Intel Core i7' }, { memory: 16 }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b8f"), + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [{ brand: 'Apple' }, { model: 'iPhone 12' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b90"), + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [{ brand: 'Samsung' }, { model: 'Galaxy Tab S7' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b92"), + product: 'mouse', + price: 50, + stock: 25, + discount: null, + specifications: [] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b93"), + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [{ size: 27 }, { resolution: '4K' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b95"), + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [{ type: 'flatbed' }] + } +] +``` + +In the above output, the query returns all documents where the `specifications` field exists, even when the `field` has an empty value. + +If you want to find documents where the `specifications` field exists and has a specific value, use the `$exists` operator in conjunction with other operators. + +**Example:** The following query returns all documents where the `specifications` field exists and its value is an array: + +```js +db.electronics.find({ + specifications: { + $exists: true, + $type: 'array' + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a32fc7cf72d6203bb45b8e"), + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [{ processor: 'Intel Core i7' }, { memory: 16 }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b8f"), + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [{ brand: 'Apple' }, { model: 'iPhone 12' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b90"), + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [{ brand: 'Samsung' }, { model: 'Galaxy Tab S7' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b92"), + product: 'mouse', + price: 50, + stock: 25, + discount: null, + specifications: [] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b93"), + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [{ size: 27 }, { resolution: '4K' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b95"), + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [{ type: 'flatbed' }] + } +] +``` + +## $type + +_Syntax_: `{ : { $type: } }` + +Use the `$type` operator to select documents where the data type of a field matches the specified BSON type + +The `` parameter can be the type code or alias of the particular data type. + +The following table lists the available BSON type codes and their corresponding aliases: + +| Type code | Type | Alias | +| --------- | ------------------ | --------- | +| 1 | Double | double | +| 2 | String | string | +| 3 | Object | object | +| 4 | Array | array | +| 5 | Binary data | binData | +| 7 | ObjectId | objectId | +| 8 | Boolean | bool | +| 9 | Date | date | +| 10 | Null | null | +| 11 | Regular expression | regex | +| 16 | 32-bit integer | int | +| 17 | Timestamp | timestamp | +| 18 | 64-bit integer | long | +| 19 | Decimal128 | decimal | +| -1 | Min key | minKey | +| 127 | Max key | maxKey | +| -128 | Number | number | + +:::caution +`Decimal128`, `Min Key`, and `Max Key` are not currently implemented. +FerretDB supports the alias `number` which matches the following BSON types: `Double`, `32-bit integer`, and `64-bit integer` type values. +::: + +:::info +FerretDB supports the alias `number` which matches the following BSON types: `Double`, `32-bit integer`, and `64-bit integer` type values. +::: + +**Example:** The following operation query returns all documents in the `electronics` collection where the `discount` field has a boolean data type, which can be represented with the data code `8`: + +```js +db.electronics.find({ + discount: { + $type: 8 + } +}) +``` + +This query can also be written using the alias of the specified data type. + +```js +db.electronics.find({ + discount: { + $type: 'bool' + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a32fc7cf72d6203bb45b8e"), + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [{ processor: 'Intel Core i7' }, { memory: 16 }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b8f"), + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [{ brand: 'Apple' }, { model: 'iPhone 12' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b90"), + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [{ brand: 'Samsung' }, { model: 'Galaxy Tab S7' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b93"), + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [{ size: 27 }, { resolution: '4K' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b94"), + product: 'printer', + price: 150, + stock: 35, + discount: false + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b95"), + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [{ type: 'flatbed' }] + } +] +``` diff --git a/website/versioned_docs/version-v1.14/operators/query/evaluation-operators.md b/website/versioned_docs/version-v1.14/operators/query/evaluation-operators.md new file mode 100644 index 000000000000..3a6b046ecaf0 --- /dev/null +++ b/website/versioned_docs/version-v1.14/operators/query/evaluation-operators.md @@ -0,0 +1,164 @@ +--- +sidebar_position: 5 +--- + +# Evaluation query operators + +Evaluation query operators return data based on the evaluation of a specified expression. + +| Operator | Description | +| ------------------ | ----------------------------------------------------------------------------------------------------------------- | +| [`$mod`](#mod) | Matches documents where the field element is divided by a given value and returns a the specified remainder value | +| [`$regex`](#regex) | Matches documents where a field matches a specified regular expression query | + +For the examples in this section, insert the following documents into the `catalog` collection: + +```js +db.catalog.insertMany([ + { + product: 'bottle', + price: 15, + stock: 1 + }, + { + product: 'spoon', + price: 500, + stock: 0 + }, + { + product: 'cup', + price: 100, + stock: 14 + }, + { + product: 'BoWL', + price: 56, + stock: 5 + }, + { + product: 'boTtLe', + price: 20, + stock: 3 + } +]) +``` + +## $mod + +_Syntax_: `{ : { $mod: [ , ] } }` + +The `$mod` operator matches documents where the field element divided by a given value returns a specified remainder (otherwise known as a modulus). +The mathematical operation for this is `field-value % divisor-value = modulus`. + +**Example:** The following query returns all the documents where the value of the "stock" field is evenly divisible by 2: + +```js +db.catalog.find({ + stock: { + $mod: [2, 0] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63e3ac0184f488929a3f737a"), + product: 'spoon', + price: 500, + stock: 0 + }, + { + _id: ObjectId("63e3ac0184f488929a3f737b"), + product: 'cup', + price: 100, + stock: 14 + } +] +``` + +:::caution +Note that the `$mod` expression returns an error if you only have a single element in the array, more than two elements in the array, or if the array is empty. +It also rounds down decimal input down to zero (e.g. `$mod: [ 3.5 , 2 ]` is executed as `$mod: [ 3 , 2 ]`). +::: + +## $regex + +_Syntax_: `{ : { $regex: '', $options: '' } }` + +Other syntaxes: `{ : { $regex: //, $options: '' } }` and `{ : // }`. + +To use regular expression for queries on particular fields, use the `$regex` operator. + +**Example:** The following query returns all the documents where the value of the "product" field starts with the letter "b": + +```js +db.catalog.find({ + product: { + $regex: /^b/ + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63e4ce469695494b86bf2b2d"), + product: 'bottle', + price: 15, + stock: 1 + }, + { + _id: ObjectId("63e4ce469695494b86bf2b31"), + product: 'boTtLe', + price: 20, + stock: 3 + } +] +``` + +`$options` is an optional parameter that specifies the regular expression flags to use, such as: + +- Case-insensitivity (`i`) +- Multi-line matching (`m`) +- Dot character matching (`s`) + +:::note +The regex flag for ignoring white spaces (`x`) is not currently supported. +Follow [here](https://github.com/FerretDB/FerretDB/issues/592) for more updates. +::: + +To perform case-insensitive matching, use the `i` flag in the `regex` expression. + +**Example:** The following query returns all the documents where the value of the "product" field is equal to "bottle" (case-insensitive): + +```js +db.catalog.find({ + product: { + $regex: /bottle/i + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63e3ac0184f488929a3f7379"), + product: 'bottle', + price: 15, + stock: 1 + }, + { + _id: ObjectId("63e3ac0184f488929a3f737d"), + product: 'boTtLe', + price: 20, + stock: 3 + } +] +``` diff --git a/website/versioned_docs/version-v1.14/operators/query/logical-operators.md b/website/versioned_docs/version-v1.14/operators/query/logical-operators.md new file mode 100644 index 000000000000..aec278a1fb05 --- /dev/null +++ b/website/versioned_docs/version-v1.14/operators/query/logical-operators.md @@ -0,0 +1,309 @@ +--- +sidebar_position: 2 +--- + +# Logical query operators + +Logical query operators return data based on specified query expressions that are either true or false. + +| Operator | Description | +| -------------- | -------------------------------------------------------------------- | +| [`$and`](#and) | Joins all query expressions with a logical AND operator | +| [`$or`](#or) | Joins all query expressions with a logical OR operator | +| [`$not`](#not) | Returns all documents that do NOT match a query expression | +| [`$nor`](#nor) | Returns all documents that do not match any of the query expressions | + +For the examples in this section, insert the following documents into the `catalog` collection: + +```js +db.catalog.insertMany([ + { + product: 'bottle', + price: 15, + stock: 1, + discount: true, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['black', 'silver'] + } + ] + }, + { + product: 'spoon', + price: 500, + stock: 0, + discount: true, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['silver', 'white'] + } + ] + }, + { + product: 'cup', + price: 100, + stock: 14, + discount: true, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['red', 'black', 'white'] + } + ] + }, + { + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['pink', 'white', 'red'] + } + ] + } +]) +``` + +## $and + +_Syntax_: `{ $and: [ { }, { } , ... , { } ] }` + +To satisfy more than one query condition when selecting documents, use the `$and` operator. + +**Example:** Select documents that satisfy both of these expressions in the `catalog` collection: + +- `price` field is less than `100` **AND** +- `stock` field is not `0` + +```js +db.catalog.find({ + $and: [ + { + price: { + $lt: 100 + } + }, + { + stock: { + $ne: 0 + } + } + ] +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f13"), + product: 'bottle', + price: 15, + stock: 1, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['black', 'silver'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f16"), + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['pink', 'white', 'red'] } + ] + } +] +``` + +## $or + +_Syntax_: `{ $or: [ { }, { } , ... , { } ] }` + +To satisfy either one or more conditions in a query, use the `$or` operator to join the conditions. + +**Example:** Select the documents that match these expressions: + +- `discount` field is `true` _and_ `stock` field is not `0` **OR** +- `price` field is less than or equal to `60` + +```js +db.catalog.find({ + $or: [ + { + $and: [ + { + discount: true + }, + { + stock: { + $ne: 0 + } + } + ] + }, + { + price: { + $lte: 60 + } + } + ] +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f13"), + product: 'bottle', + price: 15, + stock: 1, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['black', 'silver'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f15"), + product: 'cup', + price: 100, + stock: 14, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['red', 'black', 'white'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f16"), + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['pink', 'white', 'red'] } + ] + } +] +``` + +## $not + +_Syntax_: `{ : { $not: { } } }` + +To select documents that fail to match a particular query condition, use the `$not` operator. + +**Example:** The following operation selects documents that do not satisfy the specified expression, where the `stock` field is not less than `5`. + +```js +db.catalog.find({ + stock: { + $not: { + $lt: 5 + } + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f15"), + product: 'cup', + price: 100, + stock: 14, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['red', 'black', 'white'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f16"), + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['pink', 'white', 'red'] } + ] + } +] +``` + +## $nor + +_Syntax_: `{ $nor: [ { }, { }, ... { } ] }` + +To select documents that fail to match any of the conditions in a specified query, use the `$nor` operator. + +**Example:** Select the documents that fail to match any of these conditions: + +- `discount` field is `true` _and_ `stock` field is not `0` +- `price` field is less than or equal to `60` + +```js +db.catalog.find({ + $nor: [ + { + $and: [ + { + discount: true + }, + { + stock: { + $ne: 0 + } + } + ] + }, + { + price: { + $lte: 60 + } + } + ] +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f14"), + product: 'spoon', + price: 500, + stock: 0, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['silver', 'white'] } + ] + } +] +``` diff --git a/website/versioned_docs/version-v1.14/operators/update/_category_.yml b/website/versioned_docs/version-v1.14/operators/update/_category_.yml new file mode 100644 index 000000000000..192683635dc2 --- /dev/null +++ b/website/versioned_docs/version-v1.14/operators/update/_category_.yml @@ -0,0 +1,9 @@ +--- +label: Update Operators +position: 2 +link: + type: generated-index + slug: /update/ + description: > + The section contains all the different types of update operators available + on FerretDB diff --git a/website/versioned_docs/version-v1.14/operators/update/array-update-operators.md b/website/versioned_docs/version-v1.14/operators/update/array-update-operators.md new file mode 100644 index 000000000000..6c7c6df4bad7 --- /dev/null +++ b/website/versioned_docs/version-v1.14/operators/update/array-update-operators.md @@ -0,0 +1,215 @@ +--- +sidebar_position: 1 +--- + +# Array update operators + +Array update operators allow you to modify the elements of an array field in a document. + +| Operator | Description | +| ------------------------ | -------------------------------------------------------------------------------------------- | +| [`$push`](#push) | Adds an element to an array | +| [`$addToSet`](#addtoset) | Adds elements to a specific array as long as the element does not already exist in the array | +| [`$pop`](#pop) | Removes either the first or the last element of an array | +| [`$pullAll`](#pullall) | Removes all matching values in a specified query from an array | + +## $push + +The `$push` operator updates a document by adding an element to a specified array. +If the array does not exist, a new array is created with the element added to it. + +Insert the following document into a `store` collection: + +```js +db.store.insertMany([ + { _id: 1, items: ['pens', 'pencils', 'paper', 'erasers', 'rulers'] } +]) +``` + +**Example:** Use the `$push` operator to add an element to an existing array. + +```js +db.store.updateOne({ _id: 1 }, { $push: { items: 'markers' } }) +``` + +After the operation, the updated document looks like this: + +```json5 +[ + { + _id: 1, + items: ['pens', 'pencils', 'paper', 'erasers', 'rulers', 'markers'] + } +] +``` + +## $addToSet + +The `$addToSet` operator updates an array by adding a specified element to an array if the element does not already exist in the array. +If the specified element exists in the array, the `$addToSet` operator will not modify the array. + +Insert the following documents into a `store` collection: + +```js +db.store.insertMany([{ _id: 1, items: ['pens', 'pencils'] }]) +``` + +**Example:** Use the `$addToSet` operator to update the array with non-existing elements. + +```js +db.store.updateOne({ _id: 1 }, { $addToSet: { items: 'paper' } }) +``` + +The document is subsequently updated with the new element, as depicted below: + +```json5 +[{ _id: 1, items: ['pens', 'pencils', 'paper'] }] +``` + +**Example:** Use the `$addToSet` operator to update the array with already existing elements. + +```js +db.store.updateOne({ _id: 1 }, { $addToSet: { items: 'pens' } }) +``` + +Since the array already contains the element, there won't be any changes. + +```json5 +[{ _id: 1, items: ['pens', 'pencils', 'paper'] }] +``` + +:::note +The `$addToSet` is different from the `$push` operator which adds the element to the array either it exists or not. +::: + +**Example:** Use the `$addToSet` operator for non-existing array fields. + +If the array field does not exist in the document, the `$addToSet` operator will create the field and add the element to the array. + +```js +db.store.updateOne({ _id: 1 }, { $addToSet: { colors: 'red' } }) +``` + +The updated document looks like this: + +```json5 +[{ _id: 1, items: ['pens', 'pencils', 'paper'], colors: ['red'] }] +``` + +## $pop + +With the `$pop` operator, you can update a document by removing the first or last element of an array. +Assign a value of `-1` to remove the first element of an array, or `1` to remove the last element. + +Insert this document into a `products` collection: + +```js +db.products.insertMany([ + { _id: 1, items: ['pens', 'pencils', 'paper', 'erasers', 'rulers'] } +]) +``` + +**Example:** Use the `$pop` operator to remove the first element of an array. + +```js +db.products.updateOne({ _id: 1 }, { $pop: { items: -1 } }) +``` + +The document is subsequently updated with the first element `pens` removed, as depicted below: + +```json5 +[ + { + _id: 1, + items: ['pencils', 'paper', 'erasers', 'rulers'] + } +] +``` + +To remove the last element of the array, assign `1` as the value for the `$pop` operator. + +```js +db.products.updateOne({ _id: 1 }, { $pop: { items: 1 } }) +``` + +The updated now looks like this: + +```json5 +[ + { + _id: 1, + items: ['pencils', 'paper', 'erasers'] + } +] +``` + +## $pullAll + +The `$pullAll` operator removes all the matching elements in a specified query from an array. + +Insert the following document into a `store` collection: + +```js +db.store.insertMany([ + { _id: 1, items: ['pens', 'pencils', 'paper', 'erasers', 'rulers'] } +]) +``` + +**Example:** Use the `$pullAll` operator to remove multiple elements from an array. + +```js +db.store.updateOne( + { _id: 1 }, + { $pullAll: { items: ['pens', 'pencils', 'paper'] } } +) +``` + +After removing all instances of the specified array elements, the document is updated as follows: + +```json5 +[ + { + _id: 1, + items: ['erasers', 'rulers'] + } +] +``` + +**Example:** Use the `$pullAll` operator to remove array of objects from an array. + +Insert the following document into a `fruits` collection: + +```js +db.fruits.insertMany([ + { + _id: 1, + fruits: [ + { type: 'apple', color: 'red' }, + { type: 'banana', color: 'yellow' }, + { type: 'orange', color: 'orange' } + ] + } +]) +``` + +The following query uses the `$pullAll` to remove all matching array objects from the specified document. + +```js +db.fruits.update( + { _id: 1 }, + { + $pullAll: { + fruits: [ + { type: 'apple', color: 'red' }, + { type: 'banana', color: 'yellow' } + ] + } + } +) +``` + +The updated document now looks like this: + +```json5 +[{ _id: 1, fruits: [{ type: 'orange', color: 'orange' }] }] +``` diff --git a/website/versioned_docs/version-v1.14/operators/update/field-update-operators.md b/website/versioned_docs/version-v1.14/operators/update/field-update-operators.md new file mode 100644 index 000000000000..303615272247 --- /dev/null +++ b/website/versioned_docs/version-v1.14/operators/update/field-update-operators.md @@ -0,0 +1,370 @@ +--- +sidebar_position: 1 +--- + +# Field update operators + +Field update operators allow you to modify the value of a specified field in a document when certain conditions are met. + +| Operator | Description | +| ------------------------------ | ------------------------------------------------------------------------------------------- | +| [`$set`](#set) | Assigns the value of a given field | +| [`$unset`](#unset) | Deletes the records of a field from a document | +| [`$inc`](#inc) | Increments a given field's value | +| [`$mul`](#mul) | Multiplies a given field's value by a specific value | +| [`$rename`](#rename) | Renames a given field with another name | +| [`$min`](#min) | Updates a particular field only when the specified value is lesser than the specified value | +| [`$max`](#max) | Updates a particular field only when the specified value is higher than the specified value | +| [`$currentDate`](#currentdate) | Specifies the current date and time as the value of a given field | +| [`$setOnInsert`](#setoninsert) | Inserts elements into an array only if they don't already exist | + +For the examples in this section, insert the following documents into the `employees` collection: + +```js +db.employee.insertOne({ + name: 'John Doe', + age: 35, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'Anytown', + state: 'CA' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: new Date('2021-01-01'), + endDate: null +}) +``` + +## $set + +The `$set` operator updates the value of a specified field and if the field does not exist, the `$set` operator creates a new field and adds it to the document. + +**Example:** The below query is an example that updates the value of the `city` field in the `address` embedded document. + +```js +db.employee.updateOne( + { name: 'John Doe' }, + { + $set: { + 'address.city': 'New York', + 'address.zip': '12345' + } + } +) +``` + +The above query updates the value of the `city` field in the `address` embedded document and adds a new field `zip` to it. + +This is the updated document: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 35, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA', + zip: '12345' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $unset + +The `$unset` operator deletes the specified field from a document and if the field is not present, the `$unset` operator will not do anything. + +**Example:** The below query deletes the `zip` field from the embedded document `address`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $unset: { 'address.zip': '' } }) +``` + +Below is the updated document, without the `zip` field: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 35, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $inc + +The `$inc` operator increments the value of a given field by a specified amount. +If the field is non-existent in the document, the `$inc` operator creates a new field and adds it to the document, setting the value to the specified increment amount. + +**Example:** The below query increments the value of the `age` field by `1`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $inc: { age: 1 } }) +``` + +The updated document looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 36, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $mul + +The `$mul` operator multiplies the value of a given field by a specified amount. +Similar to all most of the other field update operators, if the field is non-existent in the document, the `$mul` operator creates a new one and sets the value to `0`. + +**Example:** This example query multiplies the value of the `salary` field by `25%`, represented as `1.25`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $mul: { salary: 1.25 } }) +``` + +The updated record looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 36, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $rename + +The `$rename` operator renames a given field to another name. + +**Example:** The query below updates the `employee` collection and renames the `jobTitle` field to `title`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $rename: { jobTitle: 'title' } }) +``` + +The updated document looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 36, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null, + title: 'Manager' + } +] +``` + +## $min + +The `$min` operator compares a specified value with the value of the given field and updates the field to the specified value if the specified value is less than the current value of the field. + +**Example:** The below query updates the value of the `age` field to `30` as long as the current value is less than `30`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $min: { age: 30 } }) +``` + +Since `30` is less than `36`, the value of the `age` field is updated to `30`. +The updated document now looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 30, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null, + title: 'Manager' + } +] +``` + +## $max + +The `$max` operator compares a specified value with the value of the given field and updates the field to the specified value if the specified value is greater than the current value of the field. + +**Example:** The below query updates the value of the `age` field to `40` as long as the current value is greater than `40`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $max: { age: 40 } }) +``` + +This is what the updated document looks like: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 40, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { street: '123 Main St', city: 'New York', state: 'CA' }, + salary: 62500, + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null, + height: 0, + title: 'Manager' + } +] +``` + +## $currentDate + +The `$currentDate` operator assigns the current date as the value of a given field. +This can be as a date or timestamp. + +**Example:** To update the `startDate` field with the current date, use the following query: + +```js +db.employee.updateOne( + { name: 'John Doe' }, + { $currentDate: { startDate: true } } +) +``` + +This is the document after the update: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 40, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + startDate: ISODate('2023-03-10T01:26:35.606Z'), + endDate: null, + height: 0, + title: 'Manager' + } +] +``` + +## $setOnInsert + +The `$setOnInsert` operator sets the value of a given field if the document is inserted into a collection during an upsert operation. +If there is no insertion, the `$setOnInsert` operator does nothing. + +**Example:** Let's say you have a `stocks` collection that stores information about different stocks, and you want to update the stock information or add a new stock if it doesn't exist. +Here's an example of how `$SetOnInsert` works differently from `$set`. + +Using `$set`: + +```js +db.stocks.update( + { symbol: 'AAPL' }, + { + $set: { + price: 150, + lastUpdate: new Date() + } + }, + { upsert: true } +) +``` + +This query checks for a stock with the symbol "AAPL". +If it finds the stock, it updates the `price` and `lastUpdate` fields. +If it doesn't find the stock, it inserts a new document with the `symbol`, `price`, and `lastUpdate` fields. + +Using `$setOnInsert`: + +```js +db.stocks.update( + { symbol: 'AAPL' }, + { + $set: { price: 150 }, + $setOnInsert: { + companyName: 'Apple Inc.', + createdAt: new Date() + } + }, + { upsert: true } +) +``` + +This query also checks for a stock with the symbol "AAPL". +If it finds the stock, it updates only the `price` field. +If it doesn't find the stock, it inserts a new document with the `symbol`, `price`, `companyName`, and `createdAt` fields. +The `companyName` and `createdAt` fields are only added when a new document is inserted. + +Comparing both examples, the `$set` operator updates or inserts the specified fields in both cases. +On the other hand, the `$setOnInsert` operator sets the specified fields only when a new document is inserted, leaving existing documents unchanged. diff --git a/website/versioned_docs/version-v1.14/pushdown.md b/website/versioned_docs/version-v1.14/pushdown.md new file mode 100644 index 000000000000..c6f0f228cfcf --- /dev/null +++ b/website/versioned_docs/version-v1.14/pushdown.md @@ -0,0 +1,54 @@ +--- +sidebar_position: 7 +hide_table_of_contents: true +--- + +# Query pushdown + +**Query pushdown** is the method of optimizing a query by reducing the amount of data read and processed. +It saves memory space, network bandwidth, and reduces the query execution time by moving some parts +of the query execution closer to the data source. + +Initially FerretDB retrieved all data related to queried collection, and applies filters on its own, making +it possible to implement complex logic safely and quickly. +To make this process more efficient, we minimize the amount of incoming data, by applying WHERE clause on SQL queries. + +:::info +You can learn more about query pushdown in our [blog post](https://blog.ferretdb.io/ferretdb-fetches-data-query-pushdown/). +::: + +## Supported types and operators + +The following table shows all operators and types that FerretDB pushdowns on PostgreSQL backend. +If filter uses type and operator, that's marked as pushdown-supported on this list, +FerretDB will prefetch less data, resulting with more performent query. + +If your application requires better performance for specific operation, +feel free to share this with us in our [community](/#community)! + +:::tip +As query pushdown allows developers to implement query optimizations separately from the features, +the table will be updated frequently. +::: + + + + +| | Object | Array | Double | String | Binary | ObjectID | Boolean | Date | Null | Regex | Integer | Timestamp | Long | +| ------ | ------ | ----- | ----------------------- | ------ | ------ | -------- | ------- | ---- | ---- | ----- | ------- | --------- | ----------------------- | +| `=` | ✖️ | ✖️ | ⚠️ [[1]](#1) | ✅ | ✖️ | ✅ | ✅ | ✅ | ✖️ | ✖️ | ✅ | ✖️ | ⚠️ [[1]](#1) | +| `$eq` | ✖️ | ✖️ | ⚠️ [[1]](#1) | ✅ | ✖️ | ✅ | ✅ | ✅ | ✖️ | ✖️ | ✅ | ✖️ | ⚠️ [[1]](#1) | +| `$gt` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$gte` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$lt` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$lte` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$in` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$ne` | ✖️ | ✖️ | ⚠️ [[1]](#1) | ✅ | ✖️ | ✅ | ✅ | ✅ | ✖️ | ✖️ | ✅ | ✖️ | ⚠️ [[1]](#1) | +| `$nin` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | + +###### [1] {#1} + +Numbers outside the range of the safe IEEE 754 precision (`< -9007199254740991.0, 9007199254740991.0 >`), +will prefetch all numbers larger/smaller than max/min value of the range. + + diff --git a/website/versioned_docs/version-v1.14/quickstart-guide/_category_.yml b/website/versioned_docs/version-v1.14/quickstart-guide/_category_.yml new file mode 100644 index 000000000000..ff1c769eb893 --- /dev/null +++ b/website/versioned_docs/version-v1.14/quickstart-guide/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Get Started +position: 3 +link: + type: generated-index + slug: /quickstart-guide/ # referenced in README.md + description: > + Learn to install FerretDB on your local machine diff --git a/website/versioned_docs/version-v1.14/quickstart-guide/deb.md b/website/versioned_docs/version-v1.14/quickstart-guide/deb.md new file mode 100644 index 000000000000..d3c9e4f4c0ba --- /dev/null +++ b/website/versioned_docs/version-v1.14/quickstart-guide/deb.md @@ -0,0 +1,37 @@ +--- +sidebar_position: 2 +--- + +# DEB package + +To install the `.deb` packages for FerretDB on your Debian, Ubuntu, and other `.deb`-based systems, +you can use `dpkg` tool. + +Download the latest FerretDB `.deb` package from [our release pages](https://github.com/FerretDB/FerretDB/releases/latest), +rename it to `ferretdb.deb`, +then run the following command in your terminal: + +```sh +sudo dpkg -i ferretdb.deb +``` + +You can check that FerretDB was installed by running + +```sh +ferretdb --version +``` + +FerretDB does not automatically install PostgreSQL or other backends. +To install PostgreSQL, run the following commands: + +```sh +sudo apt update +sudo apt install -y postgresql +``` + +Currently, our `.deb` package does not provide a SystemD unit for starting FerretDB automatically. +You have to do it manually by running `ferretdb` binary with the [correct flags](../configuration/flags.md). + +Find out more about: + +- [getting logs](../configuration/observability.md#binary-executable-logs). diff --git a/website/versioned_docs/version-v1.14/quickstart-guide/docker.md b/website/versioned_docs/version-v1.14/quickstart-guide/docker.md new file mode 100644 index 000000000000..0a3e0d9323cf --- /dev/null +++ b/website/versioned_docs/version-v1.14/quickstart-guide/docker.md @@ -0,0 +1,138 @@ +--- +sidebar_position: 1 +slug: /quickstart-guide/docker/ # referenced in README.md +description: How to set up FerretDB using Docker +--- + +# Docker + +We provide three Docker images for various deployments: +**"all-in-one"** for quick testing and experiments, +**a development image** for debugging problems, +and **a production image** for all other cases. + +All-in-one image is documented in the +[README.md file in the repository](https://github.com/FerretDB/FerretDB#quickstart). +The rest are covered below. + +## Production image + +Our [production image](https://ghcr.io/ferretdb/ferretdb) `ghcr.io/ferretdb/ferretdb` +is recommended for most deployments. +It does not include PostgreSQL or other backends, so you must run them separately. +You can do that with Docker Compose, Kubernetes, or other means. + +### PostgreSQL Setup with Docker Compose + +The following steps describe a quick local setup: + +1. Store the following in the `docker-compose.yml` file: + + ```yaml + services: + postgres: + image: postgres + environment: + - POSTGRES_USER=username + - POSTGRES_PASSWORD=password + - POSTGRES_DB=ferretdb + volumes: + - ./data:/var/lib/postgresql/data + + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27017:27017 + environment: + - FERRETDB_POSTGRESQL_URL=postgres://postgres:5432/ferretdb + + networks: + default: + name: ferretdb + ``` + + `postgres` container runs PostgreSQL that would store data in the `./data` directory on the host. + `ferretdb` runs FerretDB. + +2. Start services with `docker compose up -d`. +3. If you have `mongosh` installed, just run it to connect to FerretDB. + It will use credentials passed in `mongosh` flags or MongoDB URI to authenticate to the PostgreSQL database. + You'll also need to set `authMechanism` to `PLAIN`. + The example URI would look like: + + ```text + mongodb://username:password@127.0.0.1/ferretdb?authMechanism=PLAIN + ``` + + See [Authentication](../security/authentication.md) and + [Securing connection with TLS](../security/tls-connections.md) for more details. + + If you don't have `mongosh`, run the following command to run it inside the temporary MongoDB container, + attaching to the same Docker network: + + ```sh + docker run --rm -it --network=ferretdb --entrypoint=mongosh mongo \ + "mongodb://username:password@ferretdb/ferretdb?authMechanism=PLAIN" + ``` + +You can improve that setup by: + +- [securing connections with TLS](../security/tls-connections.md); +- adding backups. + +Find out more about: + +- [getting logs](../configuration/observability.md#docker-logs). + +### SQLite Setup with Docker Compose + +The following steps describe the setup for SQLite: + +1. Store the following in the `docker-compose.yml` file: + + ```yaml + services: + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27017:27017 + environment: + - FERRETDB_HANDLER=sqlite + volumes: + - ./state:/state + + networks: + default: + name: ferretdb + ``` + + Unlike PostgreSQL, SQLite operates serverlessly so it does not require its own service in Docker Compose. + :::note + At the moment, authentication is not available for the SQLite backend ([See Issue here](https://github.com/FerretDB/FerretDB/issues/3008)). + ::: + +2. Start services with `docker compose up -d`. +3. If you have `mongosh` installed, just run it to connect to FerretDB. + + The example URI would look like: + + ```text + mongodb://127.0.0.1:27017/ferretdb + ``` + + Similarly, if you don't have `mongosh` installed, run this command to run it inside the temporary MongoDB container, attaching to the same Docker network: + + ```text + docker run --rm -it --network=ferretdb --entrypoint=mongosh mongo \ + "mongodb://ferretdb/ferretdb" + ``` + +## Development image + +The [development image](https://ghcr.io/ferretdb/ferretdb-dev) `ghcr.io/ferretdb/ferretdb-dev` +contains the [debug build](https://pkg.go.dev/github.com/FerretDB/FerretDB/build/version#hdr-Debug_builds) +of FerretDB with test coverage instrumentation, race detector, +and other changes that make it more suitable for debugging problems. +It can be used exactly the same way as the production image, as described above. diff --git a/website/versioned_docs/version-v1.14/quickstart-guide/go.md b/website/versioned_docs/version-v1.14/quickstart-guide/go.md new file mode 100644 index 000000000000..c3a5c313aa29 --- /dev/null +++ b/website/versioned_docs/version-v1.14/quickstart-guide/go.md @@ -0,0 +1,11 @@ +--- +sidebar_position: 6 +--- + +# Go + +See https://pkg.go.dev/github.com/FerretDB/FerretDB/ferretdb. + +_This section is not currently available. +You can help FerretDB by contributing to this section. +Click the **Edit this page** link below to get started_. diff --git a/website/versioned_docs/version-v1.14/quickstart-guide/macos.md b/website/versioned_docs/version-v1.14/quickstart-guide/macos.md new file mode 100644 index 000000000000..8cd14d51dbc4 --- /dev/null +++ b/website/versioned_docs/version-v1.14/quickstart-guide/macos.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 4 +--- + +# macOS + +_This section is not currently available. +You can help FerretDB by contributing to this section. +Click the **Edit this page** link below to get started_. diff --git a/website/versioned_docs/version-v1.14/quickstart-guide/rpm.md b/website/versioned_docs/version-v1.14/quickstart-guide/rpm.md new file mode 100644 index 000000000000..8b7c2918771b --- /dev/null +++ b/website/versioned_docs/version-v1.14/quickstart-guide/rpm.md @@ -0,0 +1,36 @@ +--- +sidebar_position: 3 +--- + +# RPM package + +To install the `.rpm` packages for FerretDB on your RHEL, CentOS, and other `.rpm`-based systems, +you can use `rpm` tool. + +Download the latest FerretDB `.rpm` package from [our release pages](https://github.com/FerretDB/FerretDB/releases/latest), +rename it to `ferretdb.rpm`, +then run the following command in your terminal: + +```sh +sudo rpm -i ferretdb.rpm +``` + +You can check that FerretDB was installed by running + +```sh +ferretdb --version +``` + +FerretDB does not automatically install PostgreSQL or other backends. +To install PostgreSQL, run the following commands: + +```sh +sudo yum install -y postgresql +``` + +Currently, our `.rpm` package does not provide a SystemD unit for starting FerretDB automatically. +You have to do it manually by running `ferretdb` binary with the [correct flags](../configuration/flags.md). + +Find out more about: + +- [getting logs](../configuration/observability.md#binary-executable-logs). diff --git a/website/versioned_docs/version-v1.14/quickstart-guide/windows.md b/website/versioned_docs/version-v1.14/quickstart-guide/windows.md new file mode 100644 index 000000000000..7f6b7cb8ac49 --- /dev/null +++ b/website/versioned_docs/version-v1.14/quickstart-guide/windows.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 5 +--- + +# Windows + +_This section is not currently available. +You can help FerretDB by contributing to this section. +Click the **Edit this page** link below to get started_. diff --git a/website/versioned_docs/version-v1.14/reference/_category_.yml b/website/versioned_docs/version-v1.14/reference/_category_.yml new file mode 100644 index 000000000000..72f94748ed01 --- /dev/null +++ b/website/versioned_docs/version-v1.14/reference/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Reference +position: 14 +link: + type: generated-index + slug: /reference/ + description: > + Reference pages on diagnostic commands, operators, glossary, etc. diff --git a/website/versioned_docs/version-v1.14/reference/glossary.md b/website/versioned_docs/version-v1.14/reference/glossary.md new file mode 100644 index 000000000000..36acaf43266e --- /dev/null +++ b/website/versioned_docs/version-v1.14/reference/glossary.md @@ -0,0 +1,156 @@ +--- +sidebar_position: 2 +--- + +# Glossary + +## List of FerretDB terminologies + +_This section contains a list of common terminologies related to FerretDB_. + +### A + +#### aggregation + +A way of processing documents in a collection and passing them through various operations or stages. +See [list of supported aggregation operations and commands here](supported-commands.md#aggregation-pipelines). + +#### aggregation pipeline + +A set of operators that lets you perform complex operations that aggregate and summarize values. +See [list of supported aggregation pipeline operators](supported-commands.md#aggregation-pipeline-operators) here. + +--- + +### B + +#### Beacon + +The telemetry service of FerretDB. +See [telemetry](../telemetry.md) for more details. + +#### BSON + +BSON is a serialized binary file format for storing JSON-like documents. + +#### BSON types + +The list of types that the BSON format supports. +BSON offers support for additional data types compared to JSON, such as `timestamp`, `date`, `ObjectId`, and `binary`. + +--- + +### C + +#### collection + +A group of documents in a non-relational database. +It is comparable to a table in a relational database. + +#### CRUD + +The four basic operations of a database: Create, Read, Update, and Delete. +See [Basic FerretDB CRUD operations here](../basic-operations/index.md). + +--- + +### D + +#### database + +An organized repository for collections containing its own sets of documents, and data. + +#### database command + +The set of commands in FerretDB. +For more information, see [supported commands](supported-commands.md) for more details. + +#### document + +A record in a collection that comprises key-value pairs. +See [Documents](../understanding-ferretdb.md#documents) for more. + +#### dot notation + +Dot notation is used to reference or access the elements in an array or in an embedded document. +See [dot notation](../understanding-ferretdb.md#dot-notation) for more details. + +--- + +### F + +#### field + +Similar to columns in a relational database. +They are represented as field name-value pairs and describe the kind of data in a document. + +--- + +### I + +#### index + +A data structure used for identifying and querying records in a collection. +It helps to limit the number of documents to search through or inspect in a collection. +Examples include `_id` index, user-defined index, hashed index, and partial index. +See [Indexes](../indexes.md) for more. + +--- + +### J + +#### JSON + +An acronym for JavaScript Object Notation. +It is a structured data format with human-readable text to store data objects composed of attribute-value pairs. + +#### JSONB + +JSONB is a data type of PostgreSQL that stores JSON data as a decomposed binary format. + +#### ObjectId + +A defining 12-byte type that ensures singularity and uniques within a collection and are used to represent the default values for the `_id` fields. + +#### operator + +A keyword that starts with a `$` character to query, update, or transform data. + +--- + +### O + +#### Operation modes + +FerretDB utilizes operation modes to define its approach in handling incoming requests, serving purposes such as testing, debugging, and bug reporting. +By default, FerretDB operates in `normal` mode. +See [Operation modes](../configuration/operation-modes.md) for more details. + +--- + +### P + +#### primary key + +An immutable identifier for a record. +The primary key of a documents is stored in the `_id` field, which typically contains the `ObjectId`. + +#### proxy + +Proxy is any MongoDB-compatible database that is running in parallel with FerretDB. +It's used to test differences between FerretDB and other databases. +See [Operation modes](../configuration/operation-modes.md) for more details. + +#### PostgreSQL + +An open source relational database. +FerretDB uses PostgreSQL as a database engine. + +### S + +#### SQLite + +SQLite is a self-contained, serverless system ideal for lightweight applications. +FerretDB now offers SQLite backend support. + +--- diff --git a/website/versioned_docs/version-v1.14/reference/supported-commands.md b/website/versioned_docs/version-v1.14/reference/supported-commands.md new file mode 100644 index 000000000000..8e47062c8477 --- /dev/null +++ b/website/versioned_docs/version-v1.14/reference/supported-commands.md @@ -0,0 +1,727 @@ +--- +sidebar_position: 1 +description: This is a list of all supported commands in FerretDB +--- + +# Supported commands + + + +## Query commands + +| Command | Argument | Status | Comments | +| --------------- | -------------------------- | ------ | --------------------------------------------------------- | +| `delete` | | ✅ | Basic command is fully supported | +| | `deletes` | ✅ | | +| | `comment` | ⚠️ | | +| | `let` | ⚠️ | Unimplemented | +| | `ordered` | ✅ | | +| | `writeConcern` | ⚠️ | Ignored | +| | `q` | ✅ | | +| | `limit` | ✅ | | +| | `collation` | ❌ | Unimplemented | +| | `hint` | ⚠️ | Ignored | +| `find` | | ✅ | Basic command is fully supported | +| | `filter` | ✅ | | +| | `sort` | ✅ | | +| | `projection` | ✅ | Basic projections with fields are supported | +| | `hint` | ⚠️ | Ignored | +| | `skip` | ⚠️ | | +| | `limit` | ✅ | | +| | `batchSize` | ✅ | | +| | `singleBatch` | ✅ | | +| | `comment` | ⚠️ | | +| | `maxTimeMS` | ✅ | | +| | `readConcern` | ⚠️ | Ignored | +| | `max` | ⚠️ | Ignored | +| | `min` | ⚠️ | Ignored | +| | `returnKey` | ❌ | Unimplemented | +| | `showRecordId` | ✅ | | +| | `tailable` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2283) | +| | `oplogReplay` | ❌ | Unimplemented | +| | `noCursorTimeout` | ❌ | Unimplemented | +| | `awaitData` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2283) | +| | `allowPartialResults` | ❌ | Unimplemented | +| | `collation` | ❌ | Unimplemented | +| | `allowDiskUse` | ⚠️ | Ignored | +| | `let` | ❌ | Unimplemented | +| `findAndModify` | | ✅ | Basic command is fully supported | +| | `query` | ✅ | | +| | `sort` | ✅ | | +| | `remove` | ✅ | | +| | `update` | ✅ | | +| | `new` | ✅ | | +| | `upsert` | ✅ | | +| | `bypassDocumentValidation` | ⚠️ | Ignored | +| | `writeConcern` | ⚠️ | Ignored | +| | `maxTimeMS` | ✅ | | +| | `collation` | ❌ | Unimplemented | +| | `arrayFilters` | ❌ | Unimplemented | +| | `hint` | ⚠️ | Ignored | +| | `comment` | ⚠️ | | +| | `let` | ⚠️ | Unimplemented | +| `getMore` | | ✅ | Basic command is fully supported | +| | `batchSize` | ✅ | | +| | `maxTimeMS` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2984) | +| | `comment` | ⚠️ | Unimplemented | +| `insert` | | ✅ | Basic command is fully supported | +| | `documents` | ✅ | | +| | `ordered` | ✅ | | +| | `bypassDocumentValidation` | ⚠️ | Ignored | +| | `comment` | ⚠️ | Ignored | +| `update` | | ✅ | Basic command is fully supported | +| | `updates` | ✅ | | +| | `ordered` | ⚠️ | Ignored | +| | `writeConcern` | ⚠️ | Ignored | +| | `bypassDocumentValidation` | ⚠️ | Ignored | +| | `comment` | ⚠️ | | +| | `let` | ⚠️ | Unimplemented | +| | `q` | ✅ | | +| | `u` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2742) | +| | `c` | ⚠️ | Unimplemented | +| | `upsert` | ✅ | | +| | `multi` | ✅ | | +| | `collation` | ❌ | Unimplemented | +| | `arrayFilters` | ⚠️ | Unimplemented | +| | `hint` | ⚠️ | Ignored | + +### Update Operators + +The following operators and modifiers are available in the `update` and `findAndModify` commands. + +| Operator | Modifier | Status | Comments | +| ----------------- | ----------- | ------ | -------------------------------------------------------- | +| `$currentDate` | | ✅ | | +| `$inc` | | ✅ | | +| `$min` | | ✅ | | +| `$max` | | ✅ | | +| `$mul` | | ✅ | | +| `$rename` | | ✅ | | +| `$set` | | ✅ | | +| `$setOnInsert` | | ✅ | | +| `$unset` | | ✅ | | +| `$` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/822) | +| `$[]` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/823) | +| `$[]` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/824) | +| `$addToSet` | | ✅️ | | +| `$pop` | | ✅ | | +| `$pull` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/826) | +| `$push` | | ✅️ | | +| `$pullAll` | | ✅️ | | +| | `$each` | ✅️ | | +| | `$position` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/829) | +| | `$slice` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/830) | +| | `$sort` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/831) | +| | `$bit` | ✅️ | | + +### Projection Operators + +The following operators are available in the `find` command `projection` argument. + +| Operator | Status | Comments | +| ------------ | ------ | --------------------------------------------------------- | +| `$` | ✅️ | | +| `$elemMatch` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1710) | +| `$meta` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1712) | +| `$slice` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1711) | + +## Query Plan Cache Commands + +Related [issue](https://github.com/FerretDB/FerretDB/issues/78). + +| Command | Argument | Status | Comments | +| ----------------------- | ------------ | ------ | --------------------------------------------------------- | +| `planCacheClear` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1502) | +| | `query` | ⚠️ | | +| | `projection` | ⚠️ | | +| | `sort` | ⚠️ | | +| | `comment` | ⚠️ | | +| `planCacheClearFilters` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1503) | +| | `query` | ⚠️ | | +| | `sort` | ⚠️ | | +| | `projection` | ⚠️ | | +| | `collation` | ❌ | Unimplemented | +| | `comment` | ⚠️ | | +| `planCacheListFilters` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1504) | +| | `comment` | ⚠️ | | +| `planCacheSetFilter` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1505) | +| | `query` | ⚠️ | | +| | `sort` | ⚠️ | | +| | `projection` | ⚠️ | | +| | `collation` | ❌ | Unimplemented | +| | `indexes` | ⚠️ | | +| | `comment` | ⚠️ | | + +## Free Monitoring Commands + +| Command | Argument | Status | Comments | +| ------------------------- | ------------------- | ------ | ---------------------------------------------------------- | +| `setFreeMonitoring` | | ✅ | [Telemetry reporting](../telemetry.md) | +| | `action: "enable"` | ✅ | [`--telemetry=enable`](../telemetry.md#enable-telemetry) | +| | `action: "disable"` | ✅ | [`--telemetry=disable`](../telemetry.md#disable-telemetry) | +| `getFreeMonitoringStatus` | | ✅ | | + +## Database Operations + +### User Management Commands + +| Command | Argument | Status | Comments | +| -------------------------- | -------------------------------- | ------ | --------------------------------------------------------- | +| `createUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1491) | +| | `pwd` | ⚠️ | | +| | `customData` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `mechanisms` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropAllUsersFromDatabase` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1492) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1493) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `grantRolesToUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1494) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `revokeRolesFromUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1495) | +| | `roles` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `updateUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1496) | +| | `pwd` | ⚠️ | | +| | `customData` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `mechanisms` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `comment` | ⚠️ | | +| `usersInfo` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1497) | +| | `showCredentials` | ⚠️ | | +| | `showCustomData` | ⚠️ | | +| | `showPrivileges` | ⚠️ | | +| | `showAuthenticationRestrictions` | ⚠️ | | +| | `filter` | ⚠️ | | +| | `comment` | ⚠️ | | + +### Authentication Commands + +| Command | Argument | Status | Comments | +| -------------- | -------- | ------ | --------------------------------------------------------- | +| `authenticate` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1731) | +| `getnonce` | | ❌ | Deprecated | +| `logout` | | ✅ | | +| `saslStart` | | ✅ | | + +### Role Management Commands + +| Command | Argument | Status | Comments | +| -------------------------- | ---------------------------- | ------ | --------------------------------------------------------- | +| `createRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1528) | +| | `privileges` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1529) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropAllRolesFromDatabase` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1530) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `grantPrivilegesToRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1531) | +| | `privileges` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `grantRolesToRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1532) | +| | `roles` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `invalidateUserCache` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1533) | +| `revokePrivilegesFromRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1534) | +| | `privileges` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `revokeRolesFromRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1535) | +| | `roles` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `rolesInfo` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1536) | +| | `showPrivileges` | ⚠️ | | +| | `showBuiltinRoles` | ⚠️ | | +| | `comment` | ⚠️ | | +| `updateRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1537) | +| | `privileges` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | + +## Session Commands + +Related [issue](https://github.com/FerretDB/FerretDB/issues/8). + +Related [issue](https://github.com/FerretDB/FerretDB/issues/153). + +| Command | Argument | Status | Comments | +| -------------------------- | -------------- | ------ | --------------------------------------------------------- | +| `abortTransaction` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1547) | +| | `txnNumber` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `autocommit` | ⚠️ | | +| | `comment` | ⚠️ | | +| `commitTransaction` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1548) | +| | `txnNumber` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `autocommit` | ⚠️ | | +| | `comment` | ⚠️ | | +| `endSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1549) | +| `killAllSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1550) | +| `killAllSessionsByPattern` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1551) | +| `killSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1552) | +| `refreshSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1553) | +| `startSession` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1554) | + +## Aggregation pipelines + +Related [issue](https://github.com/FerretDB/FerretDB/issues/1917). + +| Command | Argument | Status | Comments | +| ----------- | -------- | ------ | -------- | +| `aggregate` | | ✅️ | | +| `count` | | ✅ | | +| `distinct` | | ✅ | | + +### Aggregation pipeline stages + +| Stage | Status | Comments | +| -------------------- | ------ | --------------------------------------------------------- | +| `$addFields` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/1413) | +| `$bucket` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1414) | +| `$bucketAuto` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1414) | +| `$changeStream` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1415) | +| `$changeStream` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1415) | +| `$collStats` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2447) | +| `$count` | ✅️ | | +| `$currentOp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1444) | +| `$densify` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1418) | +| `$documents` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1419) | +| `$documents` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1419) | +| `$facet` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1420) | +| `$fill` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1421) | +| `$geoNear` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1412) | +| `$graphLookup` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1422) | +| `$group` | ✅️ | | +| `$indexStats` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1424) | +| `$limit` | ✅️ | | +| `$listLocalSessions` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1426) | +| `$listSessions` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1426) | +| `$lookup` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1427) | +| `$match` | ✅ | | +| `$merge` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1429) | +| `$out` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1430) | +| `$planCacheStats` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1431) | +| `$project` | ✅ | | +| `$redact` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1433) | +| `$replaceRoot` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1434) | +| `$replaceWith` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1434) | +| `$sample` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1435) | +| `$search` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1436) | +| `$searchMeta` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1436) | +| `$set` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/1413) | +| `$setWindowFields` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1437) | +| `$skip` | ✅️ | | +| `$sort` | ✅️ | | +| `$sortByCount` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1440) | +| `$unionWith` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1441) | +| `$unset` | ✅️ | | +| `$unwind` | ✅️ | | + +### Aggregation pipeline operators + +| Operator | Status | Comments | +| ------------------------- | ------ | --------------------------------------------------------- | +| `$abs` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$accumulator` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$acos` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$acosh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$add` (arithmetic) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$add` (date) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$addToSet` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$allElementsTrue` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$and` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1455) | +| `$anyElementTrue` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$arrayElemAt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$arrayToObject` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$asin` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$asinh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$atan` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$atan2` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$atanh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$avg` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$binarySize` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1459) | +| `$bottom` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$bottomN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$bsonSize` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1459) | +| `$ceil` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$cmp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$concat` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$concatArrays` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$cond` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1457) | +| `$convert` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$cos` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$cosh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$count` | ✅️ | | +| `$covariancePop` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$covarianceSamp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$dateAdd` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateDiff` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateFromParts` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateFromString` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateSubtract` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateToParts` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateToString` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateTrunc` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dayOfMonth` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dayOfWeek` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dayOfYear` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$degreesToRadians` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$denseRank` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$derivative` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$divide` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$documentNumber` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$eq` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$exp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$expMovingAvg` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$filter` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$first` (accumulator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$first` (array operator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$firstN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$floor` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$function` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1458) | +| `$getField` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1471) | +| `$gt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$gte` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$hour` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$ifNull` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1457) | +| `$in` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$indexOfArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$indexOfBytes` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$indexOfCP` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$integral` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$isArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$isNumber` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$isoDayOfWeek` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$isoWeek` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$isoWeekYear` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$last` (accumulator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$last` (array operator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$lastN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$let` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1469) | +| `$linearFill` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$literal` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1470) | +| `$ln` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$locf` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$log` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$log10` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$lt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$lte` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$ltrim` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$map` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$max` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$maxN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$mergeObjects` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$meta` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$millisecond` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$min` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$minN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$minute` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$mod` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$month` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$multiply` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$ne` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$not` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1455) | +| `$objectToArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1461) | +| `$or` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1455) | +| `$pow` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$push` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$radiansToDegrees` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$rand` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/541) | +| `$range` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$rank` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$reduce` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$regexFind` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$regexFindAll` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$regexMatch` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$replaceAll` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$replaceOne` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$reverseArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$round` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$rtrim` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$sampleRate` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1472) | +| `$second` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$setDifference` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setEquals` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setField` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1461) | +| `$setIntersection` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setIsSubset` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setUnion` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$shift` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$sin` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$sinh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$size` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$slice` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$sortArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$split` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$sqrt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$stdDevPop` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$stdDevSamp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$strcasecmp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$strLenBytes` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$strLenCP` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$substr` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$substrBytes` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$substrCP` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$subtract` (arithmetic) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$subtract` (date) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$sum` (accumulator) | ✅️ | | +| `$sum` (operator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2680) | +| `$switch` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1457) | +| `$tan` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$tanh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$toBool` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toDate` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$toDecimal` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toDouble` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toInt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toLong` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toLower` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$toObjectId` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$top` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$topN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$toString` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toUpper` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$trim` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$trunc` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$tsIncrement` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1464) | +| `$tsSecond` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1464) | +| `$type` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$unsetField` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1461) | +| `$week` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$year` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$zip` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | + +## Administration commands + +| Command | Argument / Option | Property | Status | Comments | +| --------------------------------- | ------------------------------ | ------------------------- | ------ | --------------------------------------------------------- | +| `cloneCollectionAsCapped` | | | ❌ | | +| | `toCollection` | | ⚠️ | | +| | `size` | | ⚠️ | | +| | `writeConcern` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `collMod` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1510) | +| | `index` | | ⚠️ | | +| | | `keyPattern` | ⚠️ | | +| | | `name` | ⚠️ | | +| | | `expireAfterSeconds` | ⚠️ | | +| | | `hidden` | ⚠️ | | +| | | `prepareUnique` | ⚠️ | | +| | | `unique` | ⚠️ | | +| | `validator` | | ⚠️ | | +| | | `validationLevel` | ⚠️ | | +| | | `validationAction` | ⚠️ | | +| | `viewOn` (Views) | | ⚠️ | | +| | `pipeline` (Views) | | ⚠️ | | +| | `cappedSize` | | ⚠️ | | +| | `cappedMax` | | ⚠️ | | +| | `changeStreamPreAndPostImages` | | ⚠️ | | +| `compact` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/3466) | +| | `force` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `compactStructuredEncryptionData` | | | ❌ | | +| | `compactionTokens` | | ⚠️ | | +| `convertToCapped` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/3457) | +| | `size` | | ⚠️ | | +| | `writeConcern` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `create` | | | ✅ | | +| | `capped` | | ✅️ | | +| | `timeseries` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/177) | +| | | `timeField` | ⚠️ | | +| | | `metaField` | ⚠️ | | +| | | `granularity` | ⚠️ | | +| | `expireAfterSeconds` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2415) | +| | `clusteredIndex` | | ⚠️ | | +| | `changeStreamPreAndPostImages` | | ⚠️ | | +| | `autoIndexId` | | ⚠️ | Ignored | +| | `size` | | ✅️ | | +| | `max` | | ✅ | | +| | `storageEngine` | | ⚠️ | Ignored | +| | `validator` | | ⚠️ | Not implemented in PostgreSQL | +| | `validationLevel` | | ⚠️ | Unimplemented | +| | `validationAction` | | ⚠️ | Unimplemented | +| | `indexOptionDefaults` | | ⚠️ | Ignored | +| | `viewOn` | | ⚠️ | Unimplemented | +| | `pipeline` | | ⚠️ | Unimplemented | +| | `collation` | | ❌ | Unimplemented | +| | `writeConcern` | | ⚠️ | Ignored | +| | `encryptedFields` | | ⚠️ | | +| | `comment` | | ⚠️ | Ignored | +| `createIndexes` | | | ✅ | | +| | `indexes` | | ✅ | | +| | | `key` | ✅ | | +| | | `name` | ✅️ | | +| | | `unique` | ✅ | | +| | | `partialFilterExpression` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2448) | +| | | `sparse` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2448) | +| | | `expireAfterSeconds` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2415) | +| | | `hidden` | ❌ | Unimplemented | +| | | `storageEngine` | ❌ | Unimplemented | +| | | `weights` | ❌ | Unimplemented | +| | | `default_language` | ❌ | Unimplemented | +| | | `language_override` | ❌ | Unimplemented | +| | | `textIndexVersion` | ❌ | Unimplemented | +| | | `2dsphereIndexVersion` | ❌ | Unimplemented | +| | | `bits` | ❌ | Unimplemented | +| | | `min` | ❌ | Unimplemented | +| | | `max` | ❌ | Unimplemented | +| | | `bucketSize` | ❌ | Unimplemented | +| | | `collation` | ❌ | Unimplemented | +| | | `wildcardProjection` | ❌ | Unimplemented | +| | `writeConcern` | | ⚠️ | | +| | `commitQuorum` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `currentOp` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2399) | +| | `$ownOps` | | ⚠️ | | +| | `$all` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `drop` | | | ✅ | | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `dropDatabase` | | | ✅ | | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `dropConnections` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1511) | +| | `hostAndPort` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `dropIndexes` | | | ✅ | | +| | `index` | | ✅ | | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `filemd5` | | | ❌ | | +| `fsync` | | | ❌ | | +| `fsyncUnlock` | | | ❌ | | +| | `lock` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `getDefaultRWConcern` | | | ❌ | | +| | `inMemory` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `getClusterParameter` | | | ❌ | | +| `getParameter` | | | ❌ | | +| | `comment` | | ⚠️ | | +| `killCursors` | | | ✅ | | +| | `cursors` | | ✅ | | +| | `comment` | | ⚠️ | | +| `killOp` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1515) | +| | `op` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `listCollections` | | | ✅ | | +| | `filter` | | ✅ | | +| | `nameOnly` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/3624) | +| | `authorizedCollections` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/3770) | +| | `comment` | | ⚠️ | | +| `listDatabases` | | | ✅ | | +| | `filter` | | ✅ | | +| | `nameOnly` | | ✅ | | +| | `authorizedDatabases` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/3769) | +| | `comment` | | ⚠️ | Ignored | +| `listIndexes` | | | ✅ | | +| | `cursor.batchSize` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `logRotate` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1959) | +| | `` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `reIndex` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1516) | +| `renameCollection` | | | ✅ | | +| | `to` | | ✅ | [Issue](https://github.com/FerretDB/FerretDB/issues/2563) | +| | `dropTarget` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2565) | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `rotateCertificates` | | | ❌ | | +| `setFeatureCompatibilityVersion` | | | ❌ | | +| `setIndexCommitQuorum` | | | ❌ | | +| | `setIndexCommitQuorum` | | ⚠️ | | +| | `indexNames` | | ⚠️ | | +| | `commitQuorum` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `setParameter` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1518) | +| `setDefaultRWConcern` | | | ❌ | | +| | `defaultReadConcern` | | ⚠️ | | +| | `defaultWriteConcern` | | ⚠️ | | +| | `writeConcern` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `shutdown` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1519) | +| | `force` | | ⚠️ | | +| | `timeoutSecs` | | ⚠️ | | +| | `comment` | | ⚠️ | | + +## Diagnostic commands + +| Command | Argument | Status | Comments | +| -------------------- | ---------------------- | ------ | -------------------------------- | +| `buildInfo` | | ✅ | Basic command is fully supported | +| `collStats` | | ✅ | Basic command is fully supported | +| | `collStats` | ✅ | | +| | `scale` | ✅ | | +| `connPoolStats` | | ❌ | Unimplemented | +| `connectionStatus` | | ✅ | Basic command is fully supported | +| | `showPrivileges` | ✅ | | +| `dataSize` | | ✅ | Basic command is fully supported | +| | `keyPattern` | ⚠️ | Unimplemented | +| | `min` | ⚠️ | Unimplemented | +| | `max` | ⚠️ | Unimplemented | +| | `estimate` | ⚠️ | Ignored | +| `dbHash` | | ❌ | Unimplemented | +| | `collection` | ⚠️ | | +| `dbStats` | | ✅ | Basic command is fully supported | +| | `scale` | ✅ | | +| | `freeStorage` | ⚠️ | Unimplemented | +| `driverOIDTest` | | ⚠️ | Unimplemented | +| `explain` | | ✅ | Basic command is fully supported | +| | `verbosity` | ⚠️ | Ignored | +| | `comment` | ⚠️ | Unimplemented | +| `features` | | ❌ | Unimplemented | +| `getCmdLineOpts` | | ✅ | Basic command is fully supported | +| `getLog` | | ✅ | Basic command is fully supported | +| `hostInfo` | | ✅ | Basic command is fully supported | +| `_isSelf` | | ❌ | Unimplemented | +| `listCommands` | | ✅ | Basic command is fully supported | +| `lockInfo` | | ❌ | Unimplemented | +| `netstat` | | ❌ | Unimplemented | +| `ping` | | ✅ | Basic command is fully supported | +| `profile` | | ❌ | Unimplemented | +| | `slowms` | ⚠️ | | +| | `sampleRate` | ⚠️ | | +| | `filter` | ⚠️ | | +| `serverStatus` | | ✅ | Basic command is fully supported | +| `shardConnPoolStats` | | ❌ | Unimplemented | +| `top` | | ❌ | Unimplemented | +| `validate` | | ✅ | Basic command is fully supported | +| | `full` | ⚠️ | | +| | `repair` | ⚠️ | | +| | `metadata` | ⚠️ | | +| | `checkBSONConformance` | ⚠️ | | +| `validateDBMetadata` | | ❌ | Unimplemented | +| | `apiParameters` | ⚠️ | | +| | `db` | ⚠️ | | +| | `collections` | ⚠️ | | +| `whatsmyuri` | | ✅ | Basic command is fully supported | diff --git a/website/versioned_docs/version-v1.14/security/_category_.yml b/website/versioned_docs/version-v1.14/security/_category_.yml new file mode 100644 index 000000000000..aa19bc8c4576 --- /dev/null +++ b/website/versioned_docs/version-v1.14/security/_category_.yml @@ -0,0 +1,7 @@ +--- +label: Security +position: 13 +link: + type: generated-index + slug: /security/ + description: Authentication and TLS diff --git a/website/versioned_docs/version-v1.14/security/authentication.md b/website/versioned_docs/version-v1.14/security/authentication.md new file mode 100644 index 000000000000..ddbfe79ab29c --- /dev/null +++ b/website/versioned_docs/version-v1.14/security/authentication.md @@ -0,0 +1,105 @@ +--- +sidebar_position: 1 +slug: /security/authentication/ # referenced in error messages +description: Learn to use authentication mechanisms +--- + +# Authentication + +FerretDB does not store authentication information (usernames and passwords) itself but uses the backend's authentication mechanisms. +The default username and password can be specified in FerretDB's connection string, +but the client could use a different user by providing a username and password in MongoDB URI. +For example, if the server was started with `postgres://user1:pass1@postgres:5432/ferretdb`, +anonymous clients will be authenticated as user1, +but clients that use `mongodb://user2:pass2@ferretdb:27018/ferretdb?tls=true&authMechanism=PLAIN` MongoDB URI will be authenticated as user2. +Since usernames and passwords are transferred in plain text, +the use of [TLS](../security/tls-connections.md) is highly recommended. + +## PostgreSQL backend with default username and password + +In following examples, default username and password are specified in FerretDB's connection string `user1:pass1`. +Ensure `user1` is a PostgreSQL user with necessary +[privileges](https://www.postgresql.org/docs/current/sql-grant.html). +See more about [creating PostgreSQL user](https://www.postgresql.org/docs/current/sql-createuser.html) +and [PostgreSQL authentication methods](https://www.postgresql.org/docs/current/auth-methods.html). + +### Using `ferretdb` package + +Start `ferretdb` by specifying `--postgresql-url` with default username and password. + +```sh +ferretdb --postgresql-url=postgres://user1:pass1@localhost:5432/ferretdb +``` + +An anonymous client is authenticated with default `user1` from `--postgresql-url`. + +```sh +mongosh 'mongodb://127.0.0.1/ferretdb' +``` + +A client that specify username and password in MongoDB URI as below is authenticated as `user2`. + +```sh +mongosh 'mongodb://user2:pass2@127.0.0.1/ferretdb?authMechanism=PLAIN' +``` + +### Using Docker + +For Docker, specify `FERRETDB_POSTGRESQL_URL` with default username and password. + +```yaml +services: + postgres: + image: postgres + environment: + - POSTGRES_USER=username + - POSTGRES_PASSWORD=password + - POSTGRES_DB=ferretdb + volumes: + - ./data:/var/lib/postgresql/data + + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27017:27017 + environment: + - FERRETDB_POSTGRESQL_URL=postgres://user1:pass1@postgres:5432/ferretdb + +networks: + default: + name: ferretdb +``` + +To start `ferretdb`, use docker compose. + +```sh +docker compose up +``` + +An anonymous client is authenticated with `user1` from `FERRETDB_POSTGRESQL_URL`. +Use following command to run `mongosh` inside the temporary MongoDB container, +attached to the same Docker network. + +```sh +docker run --rm -it --network=ferretdb --entrypoint=mongosh \ + mongo 'mongodb://ferretdb/ferretdb' +``` + +A client that specify username and password in MongoDB URI as below is authenticated as `user2`. + +```sh +docker run --rm -it --network=ferretdb --entrypoint=mongosh \ + mongo 'mongodb://user2:pass2@ferretdb/ferretdb?authMechanism=PLAIN' +``` + +## Authentication Handshake + +:::note +Some drivers may still use the legacy `hello` command to complete a handshake. +::: + +If you encounter any issues while authenticating with FerretDB, try setting the Stable API version to V1 on the client as this may prevent legacy commands from being used. +Please refer to your specific driver documentation on how to set this field. + +If this does not resolve your issue please file a bug report [here](https://github.com/FerretDB/FerretDB/issues/new?assignees=ferretdb-bot&labels=code%2Fbug%2Cnot+ready&projects=&template=bug.yml). diff --git a/website/versioned_docs/version-v1.14/security/tls-connections.md b/website/versioned_docs/version-v1.14/security/tls-connections.md new file mode 100644 index 000000000000..68901490a694 --- /dev/null +++ b/website/versioned_docs/version-v1.14/security/tls-connections.md @@ -0,0 +1,121 @@ +--- +sidebar_position: 2 +description: Learn to secure connections using TLS +--- + +# TLS Connections + +It is possible to encrypt connections between FerretDB and clients by using TLS. +All you need to do is to start the server with the following flags or environment variables: + +- `--listen-tls` / `FERRETDB_LISTEN_TLS` specifies the TCP hostname and port + that will be used for listening for incoming TLS connections. + If empty, TLS listener is disabled; +- `--listen-tls-cert-file` / `FERRETDB_LISTEN_TLS_CERT_FILE` specifies the PEM encoded, TLS certificate file + that will be presented to clients; +- `--listen-tls-key-file` / `FERRETDB_LISTEN_TLS_KEY_FILE` specifies the TLS private key file + that will be used to decrypt communications; +- `--listen-tls-ca-file` / `FERRETDB_LISTEN_TLS_CA_FILE` specifies the root CA certificate file + that will be used to verify client certificates. + +Then use `tls` query parameters in MongoDB URI for the client. +You may also need to set `tlsCAFile` parameter if the system-wide certificate authority did not issue the server's certificate. +See documentation for your client or driver for more details. +Example: `mongodb://ferretdb:27018/?tls=true&tlsCAFile=companyRootCA.pem`. + +## PostgreSQL backend with TLS + +Using TLS is recommended if username and password are transferred in plain text. + +In following examples, FerretDB uses TLS certificates to secure the connection. +Example certificates are found in [build/certs](https://github.com/FerretDB/FerretDB/tree/main/build/certs). +The `ferretdb` server uses TLS server certificate file, TLS private key file and root CA certificate file. + +```text +server-certs/ +├── rootCA-cert.pem +├── server-cert.pem +└── server-key.pem +``` + +The client uses TLS client certificate file and root CA certificate file. + +```text +client-certs/ +├── client.pem +└── rootCA-cert.pem +``` + +### Using TLS with `ferretdb` package + +The example below connects to localhost PostgreSQL instance using TLS with certificates in `server-certs` directory. +Be sure to check that `server-certs` directory and files are present. + +```sh +ferretdb \ + --postgresql-url=postgres://localhost:5432/ferretdb \ + --listen-tls=:27018 \ + --listen-tls-cert-file=./server-certs/server-cert.pem \ + --listen-tls-key-file=./server-certs/server-key.pem \ + --listen-tls-ca-file=./server-certs/rootCA-cert.pem +``` + +Using `mongosh`, a client connects to ferretdb as `user2` using TLS certificates in `client-certs` directory. +Be sure to check that `client-certs` directory and files are present. + +```sh +mongosh 'mongodb://user2:pass2@127.0.0.1:27018/ferretdb?authMechanism=PLAIN&tls=true&tlsCertificateKeyFile=./client-certs/client.pem&tlsCaFile=./client-certs/rootCA-cert.pem' +``` + +### Using TLS with Docker + +For using Docker to run `ferretdb` server, `docker-compose.yml` example for TLS is provided in below. +The Docker host requires certificates `server-certs` directory, +and volume is mounted from `./server-certs` of Docker host to `/etc/certs` of Docker container. + +```yaml +services: + postgres: + image: postgres + environment: + - POSTGRES_USER=username + - POSTGRES_PASSWORD=password + - POSTGRES_DB=ferretdb + volumes: + - ./data:/var/lib/postgresql/data + + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27018:27018 + environment: + - FERRETDB_POSTGRESQL_URL=postgres://postgres:5432/ferretdb + - FERRETDB_LISTEN_TLS=:27018 + - FERRETDB_LISTEN_TLS_CERT_FILE=/etc/certs/server-cert.pem + - FERRETDB_LISTEN_TLS_KEY_FILE=/etc/certs/server-key.pem + - FERRETDB_LISTEN_TLS_CA_FILE=/etc/certs/rootCA-cert.pem + volumes: + - ./server-certs:/etc/certs + +networks: + default: + name: ferretdb +``` + +To start `ferretdb`, use docker compose. + +```sh +docker compose up +``` + +In the following example, a client connects to MongoDB URI using TLS certificates as `user2`. +It uses Docker volume to mount `./clients-certs` of Docker host to `/clients` Docker container. + +```sh +docker run --rm -it \ + --network=ferretdb \ + --volume ./client-certs:/clients \ + --entrypoint=mongosh \ + mongo 'mongodb://user2:pass2@host.docker.internal:27018/ferretdb?authMechanism=PLAIN&tls=true&tlsCertificateKeyFile=/clients/client.pem&tlsCaFile=/clients/rootCA-cert.pem' +``` diff --git a/website/versioned_docs/version-v1.14/telemetry.md b/website/versioned_docs/version-v1.14/telemetry.md new file mode 100644 index 000000000000..281fcb991ee7 --- /dev/null +++ b/website/versioned_docs/version-v1.14/telemetry.md @@ -0,0 +1,153 @@ +--- +sidebar_position: 12 +slug: /telemetry/ # referenced in many places; must not change +--- + +# Telemetry reporting + +FerretDB collects basic anonymous usage data and sends them to our telemetry service ([FerretDB Beacon](https://beacon.ferretdb.io)), +which helps us understand its usage, and how we can further increase compatibility and enhance our product. +It also enables us to provide you information about available updates. + +Your privacy is important to us, and we understand how sensitive data collection can be, +which is why we are not collecting any personally-identifying information +or share any of the data with third parties. + +The following data is collected: + +- FerretDB version +- Random instance UUID +- [Autonomous system]() number, + cloud provider region, or country derived from IP address (but the IP address itself) +- Uptime +- Backend (PostgreSQL or SQLite) version +- Installation type (Docker, package, cloud provider marketplace, self-built) +- Build configuration (Go version, build flags and tags) +- Command statistics: + - protocol operation codes (e.g. `OP_MSG`, `OP_QUERY`); + - command names (e.g. `find`, `aggregate`); + - arguments (e.g. `sort`, `$count (stage)`); + - error codes (e.g. `NotImplemented`, `InternalError`; or `ok`). + +:::info +Argument values, data field names, successful responses, or error messages are never collected. +::: + +## Version notification + +When a FerretDB update is available, +the telemetry service sends periodic notifications containing information about the latest FerretDB version. +This information is logged in the server logs and `startupWarnings` command output. + +While you may not upgrade to the latest release immediately, +ensure that you update early to take advantage of recent bug fixes, new features, and performance improvements. + +## Configure telemetry + +The telemetry reporter has three state settings: `enabled`, `disabled`, and `undecided` (default). +The latter acts as if it is `enabled` with two differences: + +- When `enabled`, the first report is sent right after FerretDB starts. + If `undecided`, the first report is delayed by one hour. + That should give you enough time to disable it if you decide to do so. +- Similarly, when `enabled`, the last report is sent right before FerretDB shuts down. + That does not happen when `undecided`. + +:::info +`undecided` state does not automatically change into `enabled` or `disabled` after the first or any other report. +Explicit user action is required (see below) to change an `undecided` state to `enabled` or `disabled`. +::: + +Telemetry reporting is always disabled for [embedded FerretDB](https://pkg.go.dev/github.com/FerretDB/FerretDB/ferretdb) +and can't be configured. + +:::info +Despite the autogenerated message by `mongosh` regarding MongoDB's free cloud-based monitoring service, please note that no data will ever be shared with MongoDB Inc. +::: + +### Disable telemetry + +We urge you not to disable telemetry reporter, as its insights will help us enhance our software. + +While we are grateful for these usage insights, we understand that not everyone is comfortable with sending them. + +:::caution +If you disable telemetry, automated version checks and information on updates will not be available. +::: + +Telemetry can be disabled using any of the following options: + +1. Pass the command-line flag `--telemetry` to the FerretDB executable with value: + `0`, `f`, `false`, `n`, `no`, `off`, `disable`, `disabled`, `optout`, `opt-out`, `disallow`, `forbid`. + + ```sh + --telemetry=disable + ``` + +2. Set the environment variable `FERRETDB_TELEMETRY`. + + ```sh + export FERRETDB_TELEMETRY=disable + ``` + +3. Set the `DO_NOT_TRACK` environment variable with any of the following values: + `1`, `t`, `true`, `y`, `yes`, `on`, `enable`, `enabled`. + + ```sh + export DO_NOT_TRACK=true + ``` + +4. Rename FerretDB executable to include a `donottrack` string. + + :::caution + If telemetry is disabled using this option, you cannot use the `--telemetry` flag or environment variables + until the `donottrack` string is removed. + ::: + +5. Use the `db.disableFreeMonitoring()` command on runtime. + + ```js + db.disableFreeMonitoring() + ``` + + :::caution + If the telemetry is set via a command-line flag, an environment variable or a filename, it's not possible + to modify its state via command. + ::: + +### Enable telemetry + +Telemetry can be explicitly enabled (see [above](#configure-telemetry)) with the command-line flag `--telemetry` +by setting one of the values: +`1`, `t`, `true`, `y`, `yes`, `on`, `enable`, `enabled`, `optin`, `opt-in`, `allow`. + +```sh +--telemetry=enable +``` + +You can also use `FERRETDB_TELEMETRY` environment variable with same values +or on runtime via `db.enableFreeMonitoring()` command. + +```sh +export FERRETDB_TELEMETRY=enable +``` + +```js +db.enableFreeMonitoring() +``` + +One case when explicitly enabling telemetry is useful is if you want to help us improve compatibility +with your application by running its integration tests or just by testing it manually. +If you leave the telemetry state undecided and your test lasts less than an hour, +we will not have data about unimplemented commands and errors. + +If you want to help us with that, please do the following: + +1. Start FerretDB with [debug logging](configuration/flags.md) and telemetry explicitly enabled. + Confirm that telemetry is enabled from the logs. +2. Test your application with integration tests or manually. +3. Gracefully stop FerretDB with `SIGTERM` or `docker stop` (not with `SIGKILL` or `docker kill`). +4. Optionally, locate instance UUID in the `state.json` file in the state directory + (`/state` for Docker, current directory otherwise) and send it to us. + That would allow us to locate your data and understand what FerretDB functionality + should be implemented or fixed to improve compatibility with your application. diff --git a/website/versioned_docs/version-v1.14/understanding-ferretdb.md b/website/versioned_docs/version-v1.14/understanding-ferretdb.md new file mode 100644 index 000000000000..c866497ea45e --- /dev/null +++ b/website/versioned_docs/version-v1.14/understanding-ferretdb.md @@ -0,0 +1,197 @@ +--- +sidebar_position: 2 +--- + +# Understanding FerretDB + +FerretDB is an open-source proxy that translates MongoDB wire protocol queries to SQL, +with PostgreSQL or SQLite as the database engine. +It uses the same commands, drivers, and tools as MongoDB. + +```mermaid +flowchart LR + A["Any application\nAny MongoDB driver"] + F{{FerretDB}} + P[(PostgreSQL)] + S[("SQLite")] + + A -- "MongoDB protocol\nBSON" --> F + F -- "PostgreSQL protocol\nSQL" --> P + F -. "SQLite library\nSQL" .-> S +``` + +:::tip +New to FerretDB? + +Check out our: + +- [Installation guide](quickstart-guide/docker.md) +- [Key differences](diff.md) +- [Basic CRUD operations](basic-operations/index.md) + +::: + +## Supported backends + +:::caution +FerretDB is under constant development. +As with any database, before moving to production, please verify if it is suitable for your application. +::: + +### PostgreSQL + +PostgreSQL backend is our main backend and is fully supported. + +PostgreSQL should be configured with `UTF8` encoding and one of the following locales: +`POSIX`, `C`, `C.UTF8`, `en_US.UTF8`. + +MongoDB databases are mapped to PostgreSQL schemas in a single PostgreSQL database that should be created in advance. +MongoDB collections are mapped to PostgreSQL tables. +MongoDB documents are mapped to rows with a single [JSONB](https://www.postgresql.org/docs/current/datatype-json.html) column. +Those mappings will change as we work on improving compatibility and performance, +but no breaking changes will be introduced without a major version bump. + +### SQLite + +We also support the [SQLite](https://www.sqlite.org/) backend. + +MongoDB databases are mapped to SQLite database files. +MongoDB collections are mapped to SQLite tables. +MongoDB documents are mapped to rows with a single [JSON1](https://www.sqlite.org/json1.html) column. +Those mappings will change as we work on improving compatibility and performance, +but no breaking changes will be introduced without a major version bump. + +### SAP HANA (alpha) + +Currently, [we are also working](https://blogs.sap.com/2022/12/13/introduction-to-sap-hana-compatibility-layer-for-mongodb-wire-protocol/) +with SAP on HANA compatibility. +It is not officially supported yet. + +## Documents + +Documents are self-describing records containing both data types and a description of the data being stored. +They are similar to rows in relational databases. +Here is an example of a single document: + +```js +{ + first: "Thomas", + last: "Edison", + invention: "Lightbulb", + birth: 1847 +} +``` + +The above data is stored in a single document. + +:::note +FerretDB follows almost the same naming conventions as MongoDB. +However, there are a few restrictions, which you can find [here](diff.md). +::: + +For complex documents, you can nest objects (subdocuments) inside a document. + +```js +{ + name: { + first: "Thomas", + last: "Edison" + }, + invention: "Lightbulb", + birth: 1847 +} +``` + +In the example above, the `name` field is a subdocument embedded into a document. + +## Dot notation + +Dot notations `(.)` are used to reference a field in an embedded document or its index position in an array. + +### Arrays + +Dot notations can be used to specify or query an array by concatenating a dot `(.)` with the index position of the field. + +```js +'array_name.index' +``` + +:::note +When using dot notations, the field name of the array and the specified value must be enclosed in quotation marks. +::: + +For example, let's take the following array field in a document: + +```js +animals: ['dog', 'cat', 'fish', 'fox'] +``` + +To reference the fourth field in the array, use the dot notation `"animals.3"`. + +Here are more examples of dot notations on arrays: + +- [Query an array](basic-operations/read.md#retrieve-documents-containing-a-specific-value-in-an-array) +- [Update an array](basic-operations/update.md#update-an-array-element) + +### Embedded documents + +To reference or query a field in an embedded document, concatenate the name of the embedded document and the field name using the dot notation. + +```js +'embedded_document_name.field' +``` + +Take the following document, for example: + +```js +{ + name:{ + first: "Tom", + last: "Barry" + }, + contact:{ + address:{ + city: "Kent", + state: "Ohio" + }, + phone: "432-124-1234" + } +} +``` + +To reference the `city` field in the embedded document, use the dot notation `"contact.address.city"`. + +For dot notation examples on embedded documents, see here: + +- [Query an embedded document](basic-operations/read.md#query-on-an-embedded-or-nested-document) +- [Update an embedded document](basic-operations/update.md#update-an-embedded-document) + +## Collections + +Collections are a repository for documents. +To some extent, they are similar to tables in a relational database. +If a collection does not exist, FerretDB creates a new one when you insert documents for the first time. +A collection may contain one or more documents. +For example, the following collection contains three documents. + +```js +{ + Scientists: [ + { + first: 'Alan', + last: 'Turing', + born: 1912 + }, + { + first: 'Thomas', + last: 'Edison', + birth: 1847 + }, + { + first: 'Nikola', + last: 'Tesla', + birth: 1856 + } + ] +} +``` diff --git a/website/versioned_docs/version-v1.15/aggregation-operations/_category_.yml b/website/versioned_docs/version-v1.15/aggregation-operations/_category_.yml new file mode 100644 index 000000000000..f6e53577a0e8 --- /dev/null +++ b/website/versioned_docs/version-v1.15/aggregation-operations/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Aggregation Operations +position: 6 +link: + type: generated-index + slug: /aggregation-operations/ + description: > + This section details aggregation operations in FerretDB, including aggregation commands, stages, and operators diff --git a/website/versioned_docs/version-v1.15/aggregation-operations/aggregation-pipeline-and-commands.md b/website/versioned_docs/version-v1.15/aggregation-operations/aggregation-pipeline-and-commands.md new file mode 100644 index 000000000000..afacda117a23 --- /dev/null +++ b/website/versioned_docs/version-v1.15/aggregation-operations/aggregation-pipeline-and-commands.md @@ -0,0 +1,77 @@ +--- +sidebar_position: 1 +--- + +# Aggregation pipeline and commands + +Aggregation operations involve performing various operations on a large number of data records, such as data grouping, sorting, restructuring, or modifying. +These operations pass through one or more stages, which make up a pipeline. + +![aggregation stages](/img/docs/aggregation-stages.jpg) + +Each stage acts upon the returned documents of the previous stage, starting with the input documents. +As shown above, the documents pass through the pipeline with the result of the previous stage acting as input for the next stage, going from `$match` => `$group` => `$sort` stage. + +For example, insert the following documents in a `sales` collection: + +```js +db.sales.insertMany([ + { _id: 1, category: 'Electronics', price: 1000 }, + { _id: 2, category: 'Electronics', price: 800 }, + { _id: 3, category: 'Clothing', price: 30 }, + { _id: 4, category: 'Clothing', price: 50 }, + { _id: 5, category: 'Home', price: 1500 }, + { _id: 6, category: 'Home', price: 1200 }, + { _id: 7, category: 'Books', price: 20 }, + { _id: 8, category: 'Books', price: 40 } +]) +``` + +A typical aggregation pipeline would look like this: + +```js +db.sales.aggregate([ + { $match: { category: { $ne: 'Electronics' } } }, + { + $group: { + _id: '$category', + totalPrice: { $sum: '$price' }, + productCount: { $sum: 1 } + } + }, + { $sort: { totalPrice: -1 } } +]) +``` + +In the pipeline, the complex query is broken down into separate stages where the record goes through a series of transformations until it finally produces the desired result. +First, the `$match` stage filters out all documents where the `category` field is not `Electronics`. +Then, the `$group` stage groups the documents by their `category` and calculates the total price and product count for each of those category. +Finally, the `$sort` stage sorts the documents by the `totalPrice` field in descending order. + +So the above aggregation pipeline operation would return the following result: + +```json5 +[ + { _id: 'Home', totalPrice: 2700, productCount: 2 }, + { _id: 'Clothing', totalPrice: 80, productCount: 2 }, + { _id: 'Books', totalPrice: 60, productCount: 2 } +] +``` + +This section of the documentation will focus on [`aggregate` command](#aggregate-command), [aggregation stages](aggregation-stages.md), and aggregation operators. + +## `aggregate` command + +The aggregation command `aggregate` is a top-level command used for aggregating data across various pipeline stages. + +The command is used for performing aggregation operations on a collection and lets you specify aggregation operations in a pipeline consisting of one or more stages and operators for transforming and analyzing data, such as grouping, filtering, sorting, projecting, and calculating aggregates. + +```js +// Aggregation pipeline to perform aggregation operations on a collection +db.collection.aggregate([ + // Stage 1: Matching documents based on a specific field and value + { $match: { field: value } }, + // Stage 2: Grouping documents by the "category" field and calculating the sum of the "quantity" field + { $group: { _id: '$category', total: { $sum: '$quantity' } } } +]) +``` diff --git a/website/versioned_docs/version-v1.15/aggregation-operations/aggregation-stages.md b/website/versioned_docs/version-v1.15/aggregation-operations/aggregation-stages.md new file mode 100644 index 000000000000..1b27aa0a1c30 --- /dev/null +++ b/website/versioned_docs/version-v1.15/aggregation-operations/aggregation-stages.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 2 +--- + +# Aggregation stages + +Aggregation stages are a series of one or more processes in a pipeline that acts upon the returned result of the previous stage, starting with the input documents. + +| Supported aggregation stages | Description | +| ---------------------------- | ----------------------------------------------------------------------------------------------------- | +| `$count` | Returns the count of all matched documents in a specified query | +| `$group` | Groups documents based on specific value or expression and returns a single document for each group | +| `$limit` | Limits specific documents and passes the rest to the next stage | +| `$match` | Acts as a `find` operation by only returning documents that match a specified query to the next stage | +| `$project` | Specifies the fields in a document to pass to the next stage in the pipeline | +| `$skip` | Skips a specified `n` number of documents and passes the rest to the next stage | +| `$sort` | Sorts and returns all the documents based on a specified order | +| `$unset` | Specifies the fields to be removed/excluded from a document | +| `$unwind` | Deconstructs and returns a document for every element in an array field | diff --git a/website/versioned_docs/version-v1.15/basic-operations/_category_.yml b/website/versioned_docs/version-v1.15/basic-operations/_category_.yml new file mode 100644 index 000000000000..0efa62204a79 --- /dev/null +++ b/website/versioned_docs/version-v1.15/basic-operations/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Basic CRUD Operations +position: 4 +link: + type: generated-index + slug: /basic-operations/ + description: > + Perform basic CRUD operations using FerretDB diff --git a/website/versioned_docs/version-v1.15/basic-operations/create.md b/website/versioned_docs/version-v1.15/basic-operations/create.md new file mode 100644 index 000000000000..d524b993bab2 --- /dev/null +++ b/website/versioned_docs/version-v1.15/basic-operations/create.md @@ -0,0 +1,80 @@ +--- +sidebar_position: 2 +--- + +# Insert operation + +The insert operation adds a new document to a collection. + +## Insert a single document + +The `insertOne()` command is used to add a single document into a collection, using this syntax format: + +```js +db.collection.insertOne({field1: value1, field2: value2,.... fieldN: valueN}) +``` + +The example below depicts how a single document can be added to a collection. +If a collection does not exist, the insert command automatically creates one. + +```js +db.scientists.insertOne({ + name: { + firstname: 'Thomas', + lastname: 'Edison' + }, + born: 1847, + invention: 'lightbulb' +}) +``` + +If the operation is successful, you will get a response with acknowledged set to true, and the autogenerated ObjectId of the document that looks like this: + +```js +{ + acknowledged: true, + insertedId: ObjectId("6346fcafd7a4a1b0b38eb2db") +} +``` + +## Insert multiple documents at once + +A collection can contain multiple documents. +Using the `insertMany()` command, you can add multiple documents to a collection at once. + +```js +db.collection_name.insertMany([{ document1 }, { document2 }, ...{ documentN }]) +``` + +The following example shows how to insert multiple documents into a collection: + +```js +db.scientists.insertMany([ + { + name: { + firstname: 'Alan', + lastname: 'Turing' + }, + born: 1912, + invention: 'Turing Machine' + }, + { + name: { + firstname: 'Graham', + lastname: 'Bell' + }, + born: 1847, + invention: 'telephone' + }, + { + name: { + firstname: 'Ada', + lastname: 'Lovelace' + }, + born: 1815, + invention: 'computer programming' + } +]) +``` + +You can retrieve all the documents in the collection with this command: `db.scientists.find({})` diff --git a/website/versioned_docs/version-v1.15/basic-operations/delete.md b/website/versioned_docs/version-v1.15/basic-operations/delete.md new file mode 100644 index 000000000000..50bda975115a --- /dev/null +++ b/website/versioned_docs/version-v1.15/basic-operations/delete.md @@ -0,0 +1,88 @@ +--- +sidebar_position: 5 +--- + +# Delete operation + +The delete operation removes a document from the database when a given query is met. +Two methods for deleting documents in a collection include `deleteOne()` and `deleteMany()`. + +## Delete a single document + +The `deleteOne()` method removes a single document (the first document that matches the query parameter) completely from the collection. + +```js +db.collection.deleteOne({}) +``` + +Insert the following list of documents: + +```js +db.scientists.insertMany([ + { + firstname: 'Thomas', + lastname: 'Edison', + born: 1847, + invention: 'LightBulb', + nobel: true + }, + { + firstname: 'Graham', + lastname: 'Bell', + born: 1847, + invention: 'telephone', + nobel: false + }, + { + firstname: 'Nikola', + lastname: 'Tesla', + born: 1856, + invention: 'Tesla coil', + nobel: false + }, + { + firstname: 'Ada', + lastname: 'Lovelace', + born: 1815, + invention: 'Computer programming', + nobel: false + } +]) +``` + +This operation returns a response showing `acknowledged` as `true` and the `ObjectId` of the four inserted documents: + +```js +{ + acknowledged: true, + insertedIds: { + '0': ObjectId("63470121d7a4a1b0b38eb2df"), + '1': ObjectId("63470121d7a4a1b0b38eb2e0"), + '2': ObjectId("63470121d7a4a1b0b38eb2e1"), + '3': ObjectId("63470121d7a4a1b0b38eb2e2") + } +} +``` + +Next, delete a document from the collection where the field `nobel` is set to false. + +```js +db.scientists.deleteOne({ nobel: false }) +``` + +This operation returns a response that shows that a single document was deleted from the collection. + +```js +{ acknowledged: true, deletedCount: 1 } +``` + +## Deletes multiple documents + +To delete multiple documents at once, use the `deleteMany()` method. +Using the same record from earlier, let's delete all the documents with `nobel` set to false. + +```js +db.scientists.deleteMany({ nobel: false }) +``` + +This command removes all the documents in the collection that matches the query. diff --git a/website/versioned_docs/version-v1.15/basic-operations/index.md b/website/versioned_docs/version-v1.15/basic-operations/index.md new file mode 100644 index 000000000000..a125d1eaa0a4 --- /dev/null +++ b/website/versioned_docs/version-v1.15/basic-operations/index.md @@ -0,0 +1,44 @@ +--- +sidebar_position: 1 +slug: /crud-operations/ +--- + +# Performing CRUD operations + +CRUD (Create, Read, Update, and Delete) operations in FerretDB use the same protocol and drivers as MongoDB. + +## Create operations in FerretDB + +The create operation adds a new document to a collection. +If the collection does not exist, this operation will create it. +The following methods are available for adding documents to a collection: + +[`db.collection.insertOne()`](create.md#insert-a-single-document), +[`db.collection.insertMany()`](create.md#insert-multiple-documents-at-once) + +## Read operations in FerretDB + +The read operation retrieves document records in a collection. +You can also filter the documents by targeting specific criteria for retrieval. +The following commands are used to retrieve documents from a collection: + +[`db.collection.find()`](read.md#retrieve-all-documents-in-a-collection), [`db.collection.findOne()`](read.md#retrieve-a-single-document) + +The read operation can also retrieve subdocuments that are nested within a document. + +## Update operations in FerretDB + +The update operation modifies document records in a collection. +It changes existing documents in a collection according to the query criteria. +The following update operations are supported: + +[`db.collection.updateOne()`](update.md#update-a-single-document), [`db.collection.updateMany()`](update.md#update-many-documents), [`db.collection.replaceOne()`](update#replace-a-document) + +## Delete operations in FerretDB + +The delete operation removes document records from a collection. +The following delete operations are supported: + +[`db.collection.deleteOne()`](delete.md#delete-a-single-document), [`db.collection.deleteMany()`](delete.md#deletes-multiple-documents) + +Similar to the update operation, this operation retrieves documents matching specific criteria in a collection and deletes them. diff --git a/website/versioned_docs/version-v1.15/basic-operations/read.md b/website/versioned_docs/version-v1.15/basic-operations/read.md new file mode 100644 index 000000000000..bc43096aaa90 --- /dev/null +++ b/website/versioned_docs/version-v1.15/basic-operations/read.md @@ -0,0 +1,197 @@ +--- +sidebar_position: 3 +--- + +# Read operation + +The read operation retrieves documents in a collection. +You can either retrieve all the documents in a collection, or only the documents that match a given query parameter. + +## Retrieve a single document + +The `findOne()` command retrieves a single document from a collection. + +First, populate the database with a new collection containing a list of documents. + +```js +db.scientists.insertMany([ + { + name: { + firstname: 'Alan', + lastname: 'Turing' + }, + born: 1912, + invention: 'Turing Machine' + }, + { + name: { + firstname: 'Graham', + lastname: 'Bell' + }, + born: 1847, + invention: 'telephone' + }, + { + name: { + firstname: 'Ada', + lastname: 'Lovelace' + }, + born: 1815, + invention: 'computer programming' + } +]) +``` + +Run the following `findOne()` operation to retrieve a single document from the collection: + +```js +db.scientists.findOne({ invention: 'Turing Machine' }) +``` + +## Retrieve all documents in a collection + +The `find()` command is used for retrieving all the documents in a collection. + +```js +db.collection.find() +``` + +Run `db.scientists.find()` to see the complete list of documents in the collection. + +### Retrieve documents based on a specific query + +Using the `find()` command, you can also filter a collection for only the documents that match the provided query. +For example, find the document with the field `born` set as 1857. + +```js +db.scientists.find({ born: 1857 }) +``` + +### Retrieve documents using operator queries + +The operator syntax allows users to query and retrieve a document. +There are several operator methods that you can use, such as `$gt` or `$lt`. +For example, to find the list of scientists born after the 1900s, we'll need the `$gt` operator: + +```js +db.scientists.find({ born: { $gt: 1900 } }) +``` + +Here is a list of the most commonly used operators. + +`$gt`: selects records that are greater than a specific value + +`$lt`: selects records that are less than a specific value + +`$gte`: selects records greater or equal to a specific value + +`$lte`: selects records less than or equal to a specific value + +`$in`: selects any record that contains any of the items present in a defined array + +`$nin`: selects any record that does not contain any of the items in a defined array + +`$ne`: selects records that are not equal to a specific value + +`$eq`: select records that are equal to a specific value + +### Retrieve documents containing a specific value in an array + +Insert the following documents into an `employees` collection using this command: + +```js +db.employees.insertMany([ + { + name: { + first: 'Earl', + last: 'Thomas' + }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + name: { + first: 'Sam', + last: 'Johnson' + }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + name: { + first: 'Clarke', + last: 'Dane' + }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +]) +``` + +To retrieve all documents with a specific array field and value (`catalog: "printer"`), run the following command: + +```js +db.employees.find({ catalog: 'printer' }) +``` + +The response displays all the retrieved documents: + +```json5 +[ + { + _id: ObjectId("636b39f80466c61a229bbf9b"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("636b3b0e0466c61a229bbf9d"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +### Retrieve documents in an array using dot notation + +To retrieve all documents containing a specific value in an array, use dot notation to reference its position in the `employees` collection. +The following command retrieves all documents containing `"blender"` in the third field of an array: + +```js +db.employees.find({ 'catalog.2': 'blender' }) +``` + +The document that matches the array query is displayed in the response: + +```json5 +[ + { + _id: ObjectId("636b3b0e0466c61a229bbf9c"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + } +] +``` + +### Query on an embedded or nested document + +To query on an embedded document, use dot notation to specify the fields. +The following command queries on the embedded document in the`employees` collection: + +```js +db.employees.find({ 'name.first': 'Clarke' }) +``` diff --git a/website/versioned_docs/version-v1.15/basic-operations/update.md b/website/versioned_docs/version-v1.15/basic-operations/update.md new file mode 100644 index 000000000000..0030e1e69053 --- /dev/null +++ b/website/versioned_docs/version-v1.15/basic-operations/update.md @@ -0,0 +1,205 @@ +--- +sidebar_position: 4 +--- + +# Update operation + +The update operation modifies a document record in a collection, based on a given query parameter and update. +FerretDB supports update operators, such as `$set` and `$setOnInsert` to update documents in a record. + +At present, FerretDB currently supports the following update operators: + +| Operator name | Description | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `$set` | Assigns the value for an updated field to the document. | +| `$setOnInsert` | Specifies the value of a field when an update operation results in the addition of a document. However, there is no effect when it modifies an existing document. | +| `$unset` | Removes a specific field from a document. | +| `$pop` | In an array, this operator removes the first or last item. | + +## Update a single document + +Use the `updateOne()` method to update a single document in a collection. +This operation filters a collection using a query parameter, and updates given fields within that document. + +```js +db.collection.updateOne({}, {$set: {}}) +``` + +First, populate the database with a collection containing a list of documents. + +```js +db.scientists.insertMany([ + { + firstname: 'Thomas', + lastname: 'Edison', + born: 1847, + invention: 'LightBulb', + nobel: true + }, + { + firstname: 'Graham', + lastname: 'Bell', + born: 1847, + invention: 'telephone', + nobel: false + }, + { + firstname: 'Nikola', + lastname: 'Tesla', + born: 1856, + invention: 'Tesla coil', + nobel: false + }, + { + firstname: 'Ada', + lastname: 'Lovelace', + born: 1815, + invention: 'Computer programming', + nobel: false + } +]) +``` + +Using the document record in the collection, update the document where `firstname` is "Graham", and set it as "Alexander Graham". +The `updateOne()` operation will only affect the first document that's retrieved in the collection. + +```js +db.scientists.updateOne( + { + firstname: 'Graham' + }, + { + $set: { + firstname: 'Alexander Graham' + } + } +) +``` + +## Replace a document + +Besides updating a document, you can replace it completely using the `replaceOne()` method. + +```js +db.scientists.replaceOne( + { + lastname: 'Bell' + }, + { + lastname: 'Einstein', + firstname: 'Albert', + born: 1879, + invention: 'Photoelectric effect', + nobel: true + } +) +``` + +## Update many documents + +Using the `updateMany()` command, you can modify many documents at once. +In the example below, where `nobel` is set as false, update and set to true. + +```js +db.scientists.updateMany({ nobel: false }, { $set: { nobel: true } }) +``` + +This operation updates all the documents where the field `nobel` was previously false. + +## Update an array element + +The following update example uses the `employees` collection. +To populate the collection, run the following in your terminal: + +```js +db.employees.insertMany([ + { + name: { + first: 'Earl', + last: 'Thomas' + }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + name: { + first: 'Sam', + last: 'Johnson' + }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + name: { + first: 'Clarke', + last: 'Dane' + }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +]) +``` + +The following command will query and update the `catalog` array in the `employee` collection using dot notation. +The command will query the second field of the array in every document for `"pencil"`, and when there is a match, updates the first element of the array. + +```js +db.employees.updateMany( + { + 'catalog.1': 'pencils' + }, + { + $set: { + 'catalog.0': 'ruler' + } + } +) +``` + +The response from the command: + +```js +{ + acknowledged: true, + insertedId: null, + matchedCount: 1, + modifiedCount: 1, + upsertedCount: 0 +} +``` + +## Update an embedded document + +To update an embedded document, use dot notation to specify the fields to modify. +The following operation updates any embedded document that matches the specified query in the `employees` collection. + +```js +db.employees.updateMany( + { + 'name.first': 'Clarke' + }, + { + $set: { + 'name.last': 'Elliot' + } + } +) +``` + +The following response from the command shows that a single document matching the query was updated: + +```js +{ + acknowledged: true, + insertedId: null, + matchedCount: 1, + modifiedCount: 1, + upsertedCount: 0 +} +``` diff --git a/website/versioned_docs/version-v1.15/configuration/_category_.yml b/website/versioned_docs/version-v1.15/configuration/_category_.yml new file mode 100644 index 000000000000..2524e7b4b4e1 --- /dev/null +++ b/website/versioned_docs/version-v1.15/configuration/_category_.yml @@ -0,0 +1,10 @@ +--- +label: Configuration +position: 10 +link: + type: generated-index + slug: /configuration/ + description: > + This configuration section provides guidance on setting up and customizing + the FerretDB environment through various flags, variables, and operation + modes diff --git a/website/versioned_docs/version-v1.15/configuration/flags.md b/website/versioned_docs/version-v1.15/configuration/flags.md new file mode 100644 index 000000000000..aaaca18df10d --- /dev/null +++ b/website/versioned_docs/version-v1.15/configuration/flags.md @@ -0,0 +1,114 @@ +--- +sidebar_position: 1 +--- + +# Configuration flags + +FerretDB provides numerous configuration flags you can customize to suit your needs and environment. +You can always see the complete list by using `--help` flag. +To make user experience cloud native, every flag has its environment variable equivalent. +There is no configuration file. + +:::info +Some default values are overridden in [our Docker image](../quickstart-guide/docker.md). +::: + + + + + + + +## General + +| Flag | Description | Environment Variable | Default Value | +| -------------- | ----------------------------------------------------------------- | -------------------- | ------------------------------ | +| `-h`, `--help` | Show context-sensitive help | | false | +| `--version` | Print version to stdout and exit | | false | +| `--handler` | Backend handler | `FERRETDB_HANDLER` | `pg` (PostgreSQL) | +| `--mode` | [Operation mode](operation-modes.md) | `FERRETDB_MODE` | `normal` | +| `--state-dir` | Path to the FerretDB state directory
(set to `-` to disable) | `FERRETDB_STATE_DIR` | `.`
(`/state` for Docker) | + +## Interfaces + +| Flag | Description | Environment Variable | Default Value | +| ------------------------ | ------------------------------------------------------------------------------------- | ------------------------------- | -------------------------------------------- | +| `--listen-addr` | Listen TCP address | `FERRETDB_LISTEN_ADDR` | `127.0.0.1:27017`
(`:27017` for Docker) | +| `--listen-unix` | Listen Unix domain socket path | `FERRETDB_LISTEN_UNIX` | | +| `--listen-tls` | Listen TLS address (see [here](../security/tls-connections.md)) | `FERRETDB_LISTEN_TLS` | | +| `--listen-tls-cert-file` | TLS cert file path | `FERRETDB_LISTEN_TLS_CERT_FILE` | | +| `--listen-tls-key-file` | TLS key file path | `FERRETDB_LISTEN_TLS_KEY_FILE` | | +| `--listen-tls-ca-file` | TLS CA file path | `FERRETDB_LISTEN_TLS_CA_FILE` | | +| `--proxy-addr` | Proxy address | `FERRETDB_PROXY_ADDR` | | +| `--proxy-tls-cert-file` | Proxy TLS cert file path | `FERRETDB_PROXY_TLS_CERT_FILE` | | +| `--proxy-tls-key-file` | Proxy TLS key file path | `FERRETDB_PROXY_TLS_KEY_FILE` | | +| `--proxy-tls-ca-file` | Proxy TLS CA file path | `FERRETDB_PROXY_TLS_CA_FILE` | | +| `--debug-addr` | Listen address for HTTP handlers for metrics, pprof, etc
(set to `-` to disable) | `FERRETDB_DEBUG_ADDR` | `127.0.0.1:8088`
(`:8088` for Docker) | + +## Backend handlers + + + +### PostgreSQL + +[PostgreSQL backend](../understanding-ferretdb.md#postgresql) can be enabled by +`--handler=pg` flag or `FERRETDB_HANDLER=pg` environment variable. + +| Flag | Description | Environment Variable | Default Value | +| ------------------ | ------------------------------- | ------------------------- | ------------------------------------ | +| `--postgresql-url` | PostgreSQL URL for 'pg' handler | `FERRETDB_POSTGRESQL_URL` | `postgres://127.0.0.1:5432/ferretdb` | + +FerretDB uses [pgx v5](https://github.com/jackc/pgx) library for connecting to PostgreSQL. +Supported URL parameters are documented there: + +- https://pkg.go.dev/github.com/jackc/pgx/v5/pgconn#ParseConfig +- https://pkg.go.dev/github.com/jackc/pgx/v5#ParseConfig +- https://pkg.go.dev/github.com/jackc/pgx/v5/pgxpool#ParseConfig + +Additionally: + +- `pool_max_conns` parameter is set to 50 if it is unset in the URL; +- `application_name` is always set to "FerretDB"; +- `timezone` is always set to "UTC". + +### SQLite + +[SQLite backend](../understanding-ferretdb.md#sqlite) can be enabled by +`--handler=sqlite` flag or `FERRETDB_HANDLER=sqlite` environment variable. + +| Flag | Description | Environment Variable | Default Value | +| -------------- | ------------------------------------------- | --------------------- | ------------------------------------------------- | +| `--sqlite-url` | SQLite URI (directory) for 'sqlite' handler | `FERRETDB_SQLITE_URL` | `file:data/` `.`
(`file:/state/` for Docker) | + +FerretDB uses [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) library for accessing SQLite database files. +Supported URL parameters are documented there: + +- https://www.sqlite.org/uri.html +- https://pkg.go.dev/modernc.org/sqlite#Driver.Open +- https://www.sqlite.org/pragma.html + +Additionally: + +- `_pragma=auto_vacuum(none)` parameter is set if that PRAGMA is not present; +- `_pragma=busy_timeout(10000)` parameter is set if that PRAGMA is not present; +- `_pragma=journal_mode(wal)` parameter is set if that PRAGMA is not present. + +One difference is that URI should point to the existing directory (with absolute or relative path), not to a single database file. +That allows FerretDB to work with multiple databases. + +In-memory SQLite databases are fully supported. +In that case, the URI should still point to the existing directory (that will be unused). +For example: `file:./?mode=memory`. + +## Miscellaneous + +| Flag | Description | Environment Variable | Default Value | +| --------------------- | ------------------------------------------------- | ----------------------- | ------------- | +| `--log-level` | Log level: 'debug', 'info', 'warn', 'error' | `FERRETDB_LOG_LEVEL` | `info` | +| `--[no-]log-uuid` | Add instance UUID to all log messages | `FERRETDB_LOG_UUID` | | +| `--[no-]metrics-uuid` | Add instance UUID to all metrics | `FERRETDB_METRICS_UUID` | | +| `--telemetry` | Enable or disable [basic telemetry](telemetry.md) | `FERRETDB_TELEMETRY` | `undecided` | + + + + diff --git a/website/versioned_docs/version-v1.15/configuration/observability.md b/website/versioned_docs/version-v1.15/configuration/observability.md new file mode 100644 index 000000000000..aefe006758db --- /dev/null +++ b/website/versioned_docs/version-v1.15/configuration/observability.md @@ -0,0 +1,45 @@ +--- +sidebar_position: 3 +description: Observability +--- + +# Observability + +## Logging + +The log level and format can be adjusted by [configuration flags](flags.md#miscellaneous). + +Please note that the structured log format is not stable yet; field names and formatting of values might change in minor releases. + +### Docker logs + +If Docker was launched with [our quick local setup with Docker Compose](../quickstart-guide/docker.md#setup-with-docker-compose), +the following command can be used to fetch the logs. + +```sh +docker compose logs ferretdb +``` + +Otherwise, you can check a list of running Docker containers with `docker ps` +and get logs with `docker logs`: + +```sh +$ docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +13db4c8800d3 postgres "docker-entrypoint.s…" About a minute ago Up 59 seconds 5432/tcp my-postgres +44fe6f4c3527 ghcr.io/ferretdb/ferretdb "/ferretdb" About a minute ago Up 59 seconds 8080/tcp, 27018/tcp, 0.0.0.0:27017->27017/tcp my-ferretdb + +$ docker logs my-ferretdb +``` + +### Binary executable logs + +FerretDB writes logs to the standard error (`stderr`) stream. + +## Metrics + +FerretDB exposes metrics in Prometheus format on the debug handler on `http://127.0.0.1:8088/debug/metrics` by default. +There is no need to use an external exporter. +The host and port can be changed with [`--debug-addr` flag](flags.md#interfaces). + +Please note that the set of metrics is not stable yet; metric and label names and formatting of values might change in minor releases. diff --git a/website/versioned_docs/version-v1.15/configuration/operation-modes.md b/website/versioned_docs/version-v1.15/configuration/operation-modes.md new file mode 100644 index 000000000000..7d3e5c587044 --- /dev/null +++ b/website/versioned_docs/version-v1.15/configuration/operation-modes.md @@ -0,0 +1,49 @@ +--- +sidebar_position: 2 +slug: /configuration/operation-modes/ # referenced in README.md +--- + +# Operation modes + +To simplify the development and debugging of FerretDB, we support different operation modes. +Operation modes specify how FerretDB handles incoming requests. +They are useful for testing, debugging, or bug reporting. + +You can specify modes by using the `--mode` flag or `FERRETDB_MODE` variable, +which accept following types of values: `normal`, `proxy`, `diff-normal`, `diff-proxy`. + +By default FerretDB always run on `normal` mode, which means that all client requests +are processed only by FerretDB and returned to the client. + +## Proxy + +Proxy is another MongoDB-compatible database, accessible from the machine. +You can specify its connection URL with `--proxy-addr` flag or with the `FERRETDB_PROXY_ADDR` variable. + +To forward all requests to proxy and return them to the client, use `proxy` operation mode. + +## Diff modes + +Diff modes (`diff-normal`, `diff-proxy`) forward requests to both databases, and log the difference between them. + +The `diff-normal` afterwards returns the response from FerretDB and `diff-proxy` - from the specified proxy handler. + +Example diff output: + +```diff +Header diff: +--- res header ++++ proxy header +@@ -1 +1 @@ +-length: 63, id: 14, response_to: 24, opcode: OP_MSG ++length: 64, id: 229, response_to: 24, opcode: OP_MSG + +Body diff: +--- res body ++++ proxy body +@@ -10,3 +10,3 @@ + ], +- "you": "127.0.0.1:57079", ++ "you": "172.19.0.1:59824", + "ok": { +``` diff --git a/website/versioned_docs/version-v1.15/contributing/_category_.yml b/website/versioned_docs/version-v1.15/contributing/_category_.yml new file mode 100644 index 000000000000..1fd6b7a57f8b --- /dev/null +++ b/website/versioned_docs/version-v1.15/contributing/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Contributing to FerretDB +position: 15 +link: + type: generated-index + slug: /contributing/ + description: > + Follow our guide on how to contribute to FerretDB diff --git a/website/versioned_docs/version-v1.15/contributing/index.md b/website/versioned_docs/version-v1.15/contributing/index.md new file mode 100644 index 000000000000..b405171cc58c --- /dev/null +++ b/website/versioned_docs/version-v1.15/contributing/index.md @@ -0,0 +1,48 @@ +--- +sidebar_position: 1 +slug: /how-to-contribute/ +--- + +# How to contribute to FerretDB + +FerretDB is an open source project and everyone – developers and non-developers – is welcome to contribute. +If you're interested in contributing to FerretDB projects, this documentation will help you get started. + +Here are some of the current FerretDB projects that you can fork and contribute to: + +- [FerretDB](https://github.com/FerretDB/FerretDB): This is the main repository of FerretDB. +- [dance](https://github.com/FerretDB/dance): This repository contains the FerretDB integration testing tool. +- [github-actions](https://github.com/FerretDB/github-actions): This repository houses our shared GitHub Actions for FerretDB, dance, and other repositories. + +For those taking their first steps in contributing to an open source project. +Please take a look at this post on [how to contribute to open source software](https://blog.ferretdb.io/how-to-contribute-to-open-source-2022/). + +## Get started + +You don't have to be a developer to contribute to FerretDB projects, you can even get started by helping us improve this documentation. +If you have any questions or suggestions on how we can improve, kindly join our [community](/#community). +We appreciate your feedback. + +## Contributing to this documentation + +If you find anything confusing or missing in the documentation, click the "Edit this page" link at the bottom of almost every page in the documentation. +More information on contributing to the documentation can be found [here](https://github.com/FerretDB/FerretDB/blob/main/CONTRIBUTING.md#contributing-documentation). + +## Contributing to the FerretDB repository + +- To contribute to this [FerretDB project](https://github.com/FerretDB/FerretDB/), please read the [CONTRIBUTING.md](https://github.com/FerretDB/FerretDB/blob/main/CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](https://github.com/FerretDB/FerretDB/blob/main/CODE_OF_CONDUCT.md) guideline to know more. +- Is everything working as it should? + If not, please let us know by [creating an issue](https://github.com/FerretDB/FerretDB/issues/new/choose). + You can create issues for bugs, documentation, features, or enhancements. +- You can identify issues you would like to work on by looking at the [open issues](https://github.com/FerretDB/FerretDB/issues) for this repository. +- The most straightforward way to start contributing to this repository is to select issues that are labeled [good-first-issues](https://github.com/FerretDB/FerretDB/contribute) + +## Contributing to dance + +- To start contributing to the [dance repository](https://github.com/FerretDB/dance) for integration testing, follow the guidelines in the [CONTRIBUTING.md](https://github.com/FerretDB/dance/blob/main/CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](https://github.com/FerretDB/dance/blob/main/CODE_OF_CONDUCT.md) files. +- Looking for something to work on? + Check out the [open issues](https://github.com/FerretDB/dance/issues) for this repository. + +## Contributing to github-actions + +- To contribute to our [github-actions repository](https://github.com/FerretDB/github-actions/), please go through the instructions in the [CONTRIBUTING.md](https://github.com/FerretDB/github-actions/blob/main/CONTRIBUTING.md) file. diff --git a/website/versioned_docs/version-v1.15/contributing/writing-guide.md b/website/versioned_docs/version-v1.15/contributing/writing-guide.md new file mode 100644 index 000000000000..de980c209aaf --- /dev/null +++ b/website/versioned_docs/version-v1.15/contributing/writing-guide.md @@ -0,0 +1,144 @@ +--- +sidebar_position: 99 +unlisted: true # linked from CONTRIBUTING.md +--- + +# Writing guide + +## Front matter + +The front matter represents the metadata for each page. +It is written at the top of each page and must be enclosed by `---` on both sides. + +Example: + +```yaml +--- +sidebar_position: 1 +description: How to write documentation +--- +``` + +Learn more about [front matter in Docusaurus](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-docs#markdown-front-matter). + +## Names and URLs + +Use `kebab-case-with-dashes` instead of `snake_case_with_underscores` or spaces +for file names, directory names, and slugs because URL paths typically use dashes. + +Ensure that the file name/URL path matches the title of the page. +For example, if the title of your page is "Getting Started", then the file name/URL path should also be "getting-started" to maintain consistency. +The `slug` field should be the same as the file name. +Only use a different `slug` field in some special cases, such as for backward compatibility with existing links. + +## Sidebar position + +Use the `sidebar_position` in the front matter to set the order of the pages in the sidebar. +Please ensure that the `sidebar_position` is unique for each page in that directory. +For example, if there are several pages in the folder "Getting Started", let `sidebar_position` equal "1", "2", "3", "4", and so on to avoid duplication. + +## Headers + +Use sentence case for headers: `### Some header with URL`, not `### Some Header With URL`. + +## Links + +Please use relative `.md` file paths for links. +It is required for [documentation versioning](https://docusaurus.io/docs/versioning#link-docs-by-file-paths). + +Examples: + +To link to a file in the same directory, use the file name. + +- `[file in the same directory](writing-guide.md)` + +To link to file in a different directory, specify the relative file path. + +- `[file in a different directory](../basic-operations/read.md)`. + +## Images + +Please store all images under `blog` or `docs` in the `static/img` folder. + +Also, you can collate images for a specific blog post inside a single folder. +For partner blog posts, store related images in the same folder, as `/img/blog/partner-name/image.png`. + +Otherwise, name the folder appropriately using the `YYYY-MM-DD` format, for example, a typical path for an image will be `/img/blog/2023-01-01/ferretdb-image.jpg`. + +### Alt text + +Please remember to add an alternate text for images. +The alt text should provide a description of the image for the user. +When you add a banner image, please use the title of the article as the alt text. + +### Image names + +Use of two or three descriptive words written in `kebab-case-with-dashes` as the names for the images. +For example, _ferretdb-queries.jpg_. + +### Image links + +Use Markdown syntax for images with descriptive alt texts and the path. +All assets (images, gifs, videos, etc.) relating to FerretDB documentation and blog are in the `static/img/` folder. +Rather than use relative paths, we strongly suggest the following approach, since our content engine renders all images directly from the `img` folder. + +`![FerretDB logo](/img/logo-dark.png)`. + +## Code blocks + +Always specify the language in Markdown code blocks. + +For MongoDB shell commands, use `js` language. +Our tooling will automatically reformat those blocks. + +```js +db.league.find({ club: 'PSG' }) +``` + +For MongoDB shell results, use `json5` language and copy&paste the output as-is, +with unquoted field names, single quotes for strings, without trailing commas, etc. +Our tooling will not reformat those blocks. + +```json5 +[ + { + _id: ObjectId("63109e9251bcc5e0155db0c2"), + club: 'PSG', + points: 30, + average_age: 30, + discipline: { red: 5, yellow: 30 }, + qualified: false + } +] +``` + +Use `sql` for SQL queries. +Use `text` for the `psql` output and in other cases. + +```sql +SELECT _jsonb FROM "test"."_ferretdb_database_metadata" WHERE ((_jsonb->'_id')::jsonb = '"customers"'); +``` + +```text + _jsonb ---------------------------------------------------------------------------------------------------------------------------------------------- + {"$s": {"p": {"_id": {"t": "string"}, "table": {"t": "string"}}, "$k": ["_id", "table"]}, "_id": "customers", "table": "customers_c09344de"} +``` + +```text +ferretdb=# \d test._ferretdb_settings + Table "test._ferretdb_settings" + Column | Type | Collation | Nullable | Default +----------+-------+-----------+----------+--------- + settings | jsonb | | | + +ferretdb=# SELECT settings FROM test._ferretdb_settings; + settings +-------------------------------------------------------------------------------------------------- + {"$k": ["collections"], "collections": {"$k": ["groceries"], "groceries": "groceries_6a5f9564"}} +(1 row) +``` + +## Terminologies + +To be sure that you're using the right descriptive term, please check our [glossary page](../reference/glossary.md) for relevant terms and terminologies about FerretDB. +If the word is not present in the glossary page, please feel free to ask on Slack or in the blog post issue. diff --git a/website/versioned_docs/version-v1.15/diff.md b/website/versioned_docs/version-v1.15/diff.md new file mode 100644 index 000000000000..a19fdd0faba3 --- /dev/null +++ b/website/versioned_docs/version-v1.15/diff.md @@ -0,0 +1,32 @@ +--- +sidebar_position: 11 +slug: /diff/ # referenced in README.md and beacon +--- + +# Known differences + + + +1. FerretDB uses the same protocol error names and codes, but the exact error messages may be different in some cases. +2. FerretDB does not support NUL (`\0`) characters in strings. +3. FerretDB does not support nested arrays. +4. FerretDB converts `-0` (negative zero) to `0` (positive zero). +5. Document restrictions: + - document keys must not contain `.` sign; + - document keys must not start with `$` sign; + - document fields of double type must not contain `Infinity`, `-Infinity`, or `NaN` values. +6. When insert command is called, insert documents must not have duplicate keys. +7. Update command restrictions: + - update operations producing `Infinity`, `-Infinity`, or `NaN` are not supported. +8. Database and collection names restrictions: + - name cannot start with the reserved prefix `_ferretdb_`; + - database name must not include non-latin letters; + - collection name must be valid UTF-8 characters; +9. FerretDB offers the same validation rules for the `scale` parameter in both the `collStats` and `dbStats` commands. + If an invalid `scale` value is provided in the `dbStats` command, the same error codes will be triggered as with the `collStats` command. + +If you encounter some other difference in behavior, +please [join our community](/#community) to report a problem. diff --git a/website/versioned_docs/version-v1.15/indexes.md b/website/versioned_docs/version-v1.15/indexes.md new file mode 100644 index 000000000000..37f5e2e170c4 --- /dev/null +++ b/website/versioned_docs/version-v1.15/indexes.md @@ -0,0 +1,140 @@ +--- +sidebar_position: 8 +--- + +# Indexes + +Indexes are essential in improving query performance by enabling fast retrieval of relevant documents when querying large collections. + +Indexes in FerretDB are created based on a specific field(s) within documents. +Creating an index involves having a data structure that maps the values in the indexed fields to the locations of the related documents, making it possible to retrieve documents more quickly based on those fields. + +## How to create indexes + +Use the `createIndexes()` command to create an index on a collection. +You can use the `createIndex()` method to call the `createIndexes()` command. + +The `createIndexes()` command takes two arguments: a document containing the index key (fields to index and direction - either ascending or descending), and an optional document specifying the index options. + +You can create single field indexes or compound indexes. + +### Single field indexes + +Suppose a `products` collection contains the following documents: + +```json5 +{ _id: 1, name: "iPhone 12", category: "smartphone", price: 799 } +{ _id: 2, name: "iPad Pro", category: "tablet", price: 999 } +{ _id: 3, name: "Galaxy S21", category: "smartphone", price: 699 } +{ _id: 4, name: "MacBook Pro", category: "laptop", price: 1299 } +``` + +Here's an example of the `createIndex` method to create an index on the `price` field of a `products` collection: + +```js +db.products.createIndex({ price: 1 }) +``` + +This creates an ascending index on the `price` field. + +:::note +`1` specifies the index direction for ascending order. +If it's `-1`, it specifies a descending order direction for the index. +::: + +### Compound indexes + +For compound indexes, you can create an index key combining multiple fields together as a key. +Below is an example of a compound index that uses `price` and `category` fields +from the `products` collection as the index key: + +```js +db.products.createIndex({ price: 1, category: 1 }) +``` + +### Unique indexes + +You can create unique indexes to ensure that the indexed fields do not contain duplicate values. +To create a unique index, set the `unique` option as `true` when calling `createIndexes()` command. + +Below is an example of a unique index for the `name` field from the `products` collection: + +```js +db.products.createIndex({ name: 1 }, { unique: true }) +``` + +Unique indexes can be compound. +Here is an example of a unique index consisting +of the `category` and `name` fields from the `products` collection: + +```js +db.products.createIndex({ category: 1, name: 1 }, { unique: true }) +``` + +### Index creation details + +- If the `createIndexes()` command is called for a non-existent collection, it will create the collection and its given indexes. +- If the `createIndexes()` command is called for a non-existent field, an index for the field is created without creating or adding the field to an existing collection. +- If you attempt to create an index with the same name and key as an existing index, the system will not create a duplicate index. + Instead, it will simply return the name and key of the existing index, since duplicate indexes would be redundant and inefficient. +- Meanwhile, any attempt to call `createIndexes()` command for an existing index using the same name and different key, _or_ different name but the same key will return an error. + +## How to list indexes + +To display a collection's index details, use the `listIndexes()` command. +You can also use the `getIndexes()` method to call the `listIndexes()` command. + +To return the list of indexes in the `products` collection, use the following command: + +```js +db.products.getIndexes() +``` + +The returned indexes should look like this, showing the default index, single field index, and compound index. + +```js +{ + cursor: { + id: Long("0"), + ns: 'db.products', + firstBatch: [ + { v: 2, key: { _id: 1 }, name: '_id_' }, + { v: 2, key: { price: 1 }, name: 'price_1' }, + { + v: 2, + key: { price: 1, category: 1 }, + name: 'price_1_category_1' + } + ] + }, + ok: 1 +} +``` + +## How to drop indexes + +You can also drop all the indexes or a particular index in a specified collection, except the default index (`_id`). + +FerretDB supports the use of the `dropIndexes()` command. +You can also use the `dropIndex()` method to call the `dropIndexes()` command to a particular index from a collection. + +Using the returned indexes above, let's drop the index with the name `price_1`. + +```js +db.products.dropIndex('price_1') +``` + +Another way to perform this action is to use the same index document as the index you want to drop. +For the same example above, you can rewrite it as: + +```js +db.products.dropIndex({ price: 1 }) +``` + +Using the `dropIndexes()` command, specify the index as `"*"` to remove all indexes from the collection, except the `_id` index. + +```js +db.products.dropIndexes('*') +``` + +This will drop all the non-`_id` indexes from the collection. diff --git a/website/versioned_docs/version-v1.15/main.md b/website/versioned_docs/version-v1.15/main.md new file mode 100644 index 000000000000..c94611dc92ad --- /dev/null +++ b/website/versioned_docs/version-v1.15/main.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 1 +slug: / +description: This is the FerretDB documentation, containing all the details on FerretDB – the open-source MongoDB alternative that translates MongoDB wire protocol queries to SQL, with PostgreSQL or SQLite as the database engine. +--- + +# Introduction + +FerretDB is an open-source proxy that translates MongoDB wire protocol queries to SQL, +with PostgreSQL or SQLite as the database engine. + +Initially built as open-source software, MongoDB was a game-changer for many developers, +enabling them to build fast and robust applications. +Its ease of use and extensive documentation made it a top choice for many developers looking +for an open-source database. +However, all this changed when they switched to an SSPL license, +moving away from their open-source roots. + +In light of this, FerretDB was founded to become the true open-source alternative to MongoDB, +making it the go-to choice for most MongoDB users looking for an open-source alternative to MongoDB. +With FerretDB, users can run the same MongoDB protocol queries without needing to learn a new language or command. + +## Scope and current state + +FerretDB is compatible with MongoDB drivers and can be used as a direct replacement for MongoDB 5.0+. +We are constantly adding features to increase compatibility based on user feedback. + +See our [public roadmap](https://github.com/orgs/FerretDB/projects/2/views/1), +a list of [known differences with MongoDB](diff.md), +and [contributing guidelines](https://github.com/FerretDB/FerretDB/blob/main/CONTRIBUTING.md). + +## Community + +- Website and blog: https://www.ferretdb.com/. +- Twitter: [@ferret_db](https://twitter.com/ferret_db). +- Mastodon: [@ferretdb@techhub.social](https://techhub.social/@ferretdb). +- [Slack chat](https://join.slack.com/t/ferretdb/shared_invite/zt-zqe9hj8g-ZcMG3~5Cs5u9uuOPnZB8~A) for quick questions. +- [GitHub Discussions](https://github.com/FerretDB/FerretDB/discussions) for longer topics. +- [GitHub Issues](https://github.com/FerretDB/FerretDB/issues) for bugs and missing features. +- [Open Office Hours meeting](https://calendar.google.com/event?action=TEMPLATE&tmeid=NjNkdTkyN3VoNW5zdHRiaHZybXFtb2l1OWtfMjAyMTEyMTNUMTgwMDAwWiBjX24zN3RxdW9yZWlsOWIwMm0wNzQwMDA3MjQ0QGc&tmsrc=c_n37tquoreil9b02m0740007244%40group.calendar.google.com&scp=ALL) + every Monday at 18:00 UTC at [Google Meet](https://meet.google.com/mcb-arhw-qbq). + +If you want to contact FerretDB Inc., please use [this form](https://www.ferretdb.com/contact/). diff --git a/website/versioned_docs/version-v1.15/migration/_category_.yml b/website/versioned_docs/version-v1.15/migration/_category_.yml new file mode 100644 index 000000000000..d4668fd46751 --- /dev/null +++ b/website/versioned_docs/version-v1.15/migration/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Migrating to FerretDB +position: 9 +link: + type: generated-index + slug: /migration/ + description: > + This section details the procedures on how to migrate to FerretDB diff --git a/website/versioned_docs/version-v1.15/migration/migrating-from-mongodb.md b/website/versioned_docs/version-v1.15/migration/migrating-from-mongodb.md new file mode 100644 index 000000000000..1d95069f2311 --- /dev/null +++ b/website/versioned_docs/version-v1.15/migration/migrating-from-mongodb.md @@ -0,0 +1,66 @@ +--- +sidebar_position: 2 +--- + +# Migrating from MongoDB + +Before you begin this section of the migration process, go through the pre-migration process so as to ensure a successful migration from MongoDB to FerretDB: + +- [Pre-migration testing](premigration-testing.md) + +This guide will help you migrate your data from MongoDB – locally or online – to FerretDB. + +As an open-source MongoDB alternative, FerretDB is built to work with many MongoDB tools. +In that case, you can migrate your data using MongoDB native tools such as `mongodump`/`mongorestore` and `mongoexport`/`mongoimport`. + +Before you go forward with the migration, you need to have the following: + +- MongoDB connection URI +- FerretDB connection URI +- MongoDB native tools + +## Backup your MongoDB data + +To backup your MongoDB instance using `mongodump` or `mongoexport`, you'll need to set the connection string to your MongoDB instance (e.g. `"mongodb://127.0.0.1:27017"`) to run the following command: + +```sh +mongodump --uri="mongodb://:@:" +``` + +The `mongodump` command will create a dump of all the data in the instance, consisting of BSON files of all the collections. +Also, you can migrate a specific database (e.g. `--db=test`) or collection (e.g. `--collection=supply`) using their respective parameters after the `--uri` connection string. + +:::caution +If you include the database in your connection string, there's no need to specify a database name for the backup or restore process. +::: + +```sh +mongoexport --uri="mongodb://:@:" --db= --collection= --out=.json +``` + +On the other hand, `mongoexport` does not provide a direct way to export all the collections at once, like `mongodump` does. + +Instead, you need to set the connection string to connect with your preferred database and then run the command together with the parameters for the collection (`--collection=myCollection`) and the directory you want to export to (e.g. `--out=collection-name.json`). + +## Restore your data to FerretDB + +To restore or import your backed-up data to FerretDB, set the connection string to your FerretDB instance and use `mongorestore` and `mongoimport`. + +Run the following command in your terminal, from your `dump` folder: + +```sh +mongorestore --uri="mongodb://:@:/?authMechanism=PLAIN" +``` + +With this command, you can restore all the data in `dump` into your FerretDB instance. +You can also specify the database and collection (`dump//`) you want to restore from the `dump` folder, according to your preferences. + +To import your database using `mongoimport`, run the command from the terminal directory where you exported your data: + +````sh + +```sh +mongoimport--uri="mongodb://:@:/?authMechanism=PLAIN" --db= --collection= --file=.json +```` + +The command will import the specified collection you exported from your MongoDB instance to FerretDB. diff --git a/website/versioned_docs/version-v1.15/migration/premigration-testing.md b/website/versioned_docs/version-v1.15/migration/premigration-testing.md new file mode 100644 index 000000000000..fce33ba77e90 --- /dev/null +++ b/website/versioned_docs/version-v1.15/migration/premigration-testing.md @@ -0,0 +1,233 @@ +--- +sidebar_position: 1 +--- + +# Pre-migration testing + +To ensure a smooth and successful migration from MongoDB, we offer several methods through which you can test your application with FerretDB. + +## Operation modes + +We offer multiple operation modes which help facilitate the testing of your application by enabling FerretDB to act as a proxy. +For more details, refer to the [operation modes](../configuration/operation-modes.md). + +### Manual and automated testing with `diff-normal` mode + +For details on how to install FerretDB, refer to the [quickstart guide](../../quickstart-guide/). + +You can manually test your application or use integration tests, among other methods. +Afterward, you can inspect the differential output for errors or inconsistencies between responses that require your attention. + +As an example, let us say that your application performs some complex query and you'd like to test it in `diff-normal` mode. +You would do the following: + +1. Start FerretDB in `diff-normal` mode. + + This can be achieved by setting the `--mode` [flag](../configuration/flags.md) or `FERRETDB_MODE` environment variable to `diff-normal`. + By default, FerretDB starts in normal mode (`--mode=normal`/`FERRETDB_MODE=normal`). + For more details, see [operation modes](../configuration/operation-modes.md). + + Ensure to specify `--listen-addr` and `--proxy-addr` flags or set the `FERRETDB_LISTEN_ADDR` and `FERRETDB_PROXY_ADDR` environment variables. + Specify the address of your MongoDB instance for `--proxy-addr` flag or `FERRETDB_PROXY_ADDR` environment variable. + [See docs for more details](https://docs.ferretdb.io/configuration/flags/#interfaces). For example: + + ```sh + ferretdb --mode=diff-normal \ + --proxy-addr= \ + --listen-addr= \ + --postgresql-url= + ``` + + The `--listen-addr` flag or the `FERRERDB_LISTEN_ADDR` environment variable is set to `127.0.0.1:27017` by default. + +2. Run `mongosh` to connect to the `--listen-addr` and then insert some documents. +3. Run a query to fetch the first post from each author sorted by date and author. + + Please note that due to running in `diff-normal` mode, any error returned from FerretDB will be transmitted to the client, allowing us to promptly identify the issue. + In the majority of cases, this does not necessitate additional scrutiny of the diff output. + Nevertheless, if FerretDB does not handle the error, additional inspection becomes necessary. + + ```sh + # run mongosh + $ mongosh + ``` + + ```js + // insert some documents + db.posts.insertMany([ + { + title: 'title A', + body: 'some content', + author: 'Bob', + date: ISODate('2023-08-29T10:33:23.134Z') + }, + { + title: 'another title', + body: 'some content', + author: 'Bob', + date: ISODate('2023-08-28T10:33:23.134Z') + }, + { + title: 'title B', + body: 'some content', + author: 'Alice', + date: ISODate('2023-08-20T10:33:23.134Z') + }, + { + title: 'some other title', + body: 'some content', + author: 'Alice', + date: ISODate('2023-08-21T10:33:23.134Z') + } + ]) + + // run the query + db.posts.aggregate([ + { $sort: { date: 1, author: 1 } }, + { + $group: { + _id: '$author', + firstPost: { $first: '$date' } + } + } + ]) + // the below error is returned to the client: + // MongoServerError: $group accumulator "$first" is not implemented yet + ``` + +### Manual and automated testing with `diff-proxy` mode + +Continuing with the same example above, we can further examine the diff output while in `diff-proxy` mode. + +1. Run FerretDB in `diff-proxy` mode. + This can again be achieved by using the `--mode` [flag](../configuration/flags.md) or by setting the `FERRETDB_MODE` environment variable to `diff-proxy`. +2. Follow the same instructions as the one for `diff-normal` above to run FerretDB in `diff-proxy` mode and re-run the query. + + ```js + db.posts.aggregate([ + { $sort: { date: 1, author: 1 } }, + { + $group: { + _id: '$author', + firstPost: { $first: '$date' } + } + } + ]) + // the query was handled by MongoDB, so the following documents are returned: + // { _id: 'Alice', firstPost: ISODate("2023-08-20T10:33:23.134Z") } + // { _id: 'Bob', firstPost: ISODate("2023-08-28T10:33:23.134Z") } + ``` + +In the diff output below, however, we have discovered that the query cannot be serviced by our application because the `$first` accumulator operator is not implemented in FerretDB. + +```diff +2023-08-29T13:25:09.048+0200 WARN // 127.0.0.1:33522 -> 127.0.0.1:27017 clientconn/conn.go:360 Header diff: +--- res header ++++ proxy header +@@ -1 +1 @@ +-length: 140, id: 2, response_to: 156, opcode: OP_MSG ++length: 181, id: 360, response_to: 156, opcode: OP_MSG + +Body diff: +--- res body ++++ proxy body +@@ -7,13 +7,41 @@ + "$k": [ +- "ok", +- "errmsg", +- "code", +- "codeName" ++ "cursor", ++ "ok" + ], ++ "cursor": { ++ "$k": [ ++ "firstBatch", ++ "id", ++ "ns" ++ ], ++ "firstBatch": [ ++ { ++ "$k": [ ++ "_id", ++ "firstPost" ++ ], ++ "_id": "Alice", ++ "firstPost": { ++ "$d": 1692527603134 ++ } ++ }, ++ { ++ "$k": [ ++ "_id", ++ "firstPost" ++ ], ++ "_id": "Bob", ++ "firstPost": { ++ "$d": 1693218803134 ++ } ++ } ++ ], ++ "id": { ++ "$l": "0" ++ }, ++ "ns": "test.posts" ++ }, + "ok": { +- "$f": 0 +- }, +- "errmsg": "$group accumulator \"$first\" is not implemented yet", +- "code": 238, +- "codeName": "NotImplemented" ++ "$f": 1 ++ } + }, +``` + +### Response metrics + +Metrics are captured and written to standard output (`stdout`) upon exiting in [Debug builds](https://pkg.go.dev/github.com/FerretDB/FerretDB/build/version#hdr-Debug_builds). +This is a useful way to quickly determine what commands are not implemented for the client requests sent by your application. +In the metrics provided below, we can observe that the `$first` accumulator operator was invoked 18 times within the aggregate command, and the `findAndModify` command was executed 6 times with a `fields` projection document. +Both of these operations resulted in `result="NotImplemented"`. +To address this issue, it's essential to carefully inspect any result that lacks an `ok` value. + +```text +# HELP ferretdb_client_requests_total Total number of requests. +# TYPE ferretdb_client_requests_total counter +ferretdb_client_requests_total{command="aggregate",opcode="OP_MSG"} 105 +ferretdb_client_requests_total{command="find",opcode="OP_MSG"} 398 +ferretdb_client_requests_total{command="findAndModify",opcode="OP_MSG"} 6 +ferretdb_client_requests_total{command="hello",opcode="OP_MSG"} 4 +ferretdb_client_requests_total{command="insert",opcode="OP_MSG"} 10 +ferretdb_client_requests_total{command="ismaster",opcode="OP_MSG"} 17 +ferretdb_client_requests_total{command="unknown",opcode="OP_QUERY"} 28 +ferretdb_client_requests_total{command="update",opcode="OP_MSG"} 59 +# HELP ferretdb_client_responses_total Total number of responses. +# TYPE ferretdb_client_responses_total counter +ferretdb_client_responses_total{argument="$first (accumulator)",command="aggregate",opcode="OP_MSG",result="NotImplemented"} 18 +ferretdb_client_responses_total{argument="fields",command="findAndModify",opcode="OP_MSG",result="NotImplemented"} 6 +ferretdb_client_responses_total{argument="unknown",command="aggregate",opcode="OP_MSG",result="ok"} 87 +ferretdb_client_responses_total{argument="unknown",command="find",opcode="OP_MSG",result="ok"} 398 +ferretdb_client_responses_total{argument="unknown",command="hello",opcode="OP_MSG",result="ok"} 4 +ferretdb_client_responses_total{argument="unknown",command="insert",opcode="OP_MSG",result="ok"} 10 +ferretdb_client_responses_total{argument="unknown",command="ismaster",opcode="OP_MSG",result="ok"} 17 +ferretdb_client_responses_total{argument="unknown",command="unknown",opcode="OP_REPLY",result="ok"} 28 +ferretdb_client_responses_total{argument="unknown",command="update",opcode="OP_MSG",result="ok"} 59 +``` + +### Other tools + +We also have a fork of the Amazon DocumentDB Compatibility Tool [here](https://github.com/FerretDB/amazon-documentdb-tools/tree/master/compat-tool). +The tool examines files to identify queries that use unsupported operators in FerretDB. +Please note that this tool is not highly accurate and may generate inaccurate reports, as it does not parse query syntax with contextual information about the originating command. +For example, an unsupported operator might appear within a `find` or `aggregate` command, which the tool does not differentiate. +Note that we also mark operators as unsupported if they are not supported in _all_ commands, which could result in false negatives. + +Running the tool to check FerretDB compatibility: + +```sh +# clone the repository and run the compat-tool +$ git clone https://github.com/FerretDB/amazon-documentdb-tools.git && cd amazon-documentdb-tools/compat-tool +$ python3 compat.py --directory=/path/to/myapp --version=FerretDB +``` diff --git a/website/versioned_docs/version-v1.15/operators/_category_.yml b/website/versioned_docs/version-v1.15/operators/_category_.yml new file mode 100644 index 000000000000..5dd8c8338976 --- /dev/null +++ b/website/versioned_docs/version-v1.15/operators/_category_.yml @@ -0,0 +1,9 @@ +--- +label: Operators +position: 5 +link: + type: generated-index + slug: /operators/ + description: > + The complete list of operators, including query operators, update operators, + aggregation operators, etc. diff --git a/website/versioned_docs/version-v1.15/operators/query/_category_.yml b/website/versioned_docs/version-v1.15/operators/query/_category_.yml new file mode 100644 index 000000000000..75be6a917b7a --- /dev/null +++ b/website/versioned_docs/version-v1.15/operators/query/_category_.yml @@ -0,0 +1,9 @@ +--- +label: Query Operators +position: 1 +link: + type: generated-index + slug: /query/ + description: > + The list of all different types of query operators available on FerretDB, + including comparison operators, logical operators, array operators, etc. diff --git a/website/versioned_docs/version-v1.15/operators/query/array-operators.md b/website/versioned_docs/version-v1.15/operators/query/array-operators.md new file mode 100644 index 000000000000..e4943f0e00a3 --- /dev/null +++ b/website/versioned_docs/version-v1.15/operators/query/array-operators.md @@ -0,0 +1,195 @@ +--- +sidebar_position: 3 +--- + +# Array query operators + +Array query operators allow you to search for specific elements within an array field in a document. + +| Operator | Description | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| [`$all`](#all) | Selects an array that contains all elements from a given query. | +| [`$elemMatch`](#elemmatch) | Matches a document that contains an array field with at least one element that matches all the specified query criteria | +| [`$size`](#size) | Matches an array with a specified number of elements | + +For the examples in this section, insert the following documents into the `team` collection: + +```js +db.team.insertMany([ + { + id: 1, + name: 'Jack Smith', + position: 'Manager', + skills: ['leadership', 'communication', 'project management'], + contact: { + email: 'john@example.com', + phone: '123-456-7890' + }, + active: true + }, + { + id: 2, + name: 'Jane Mark', + position: 'Software Developer', + skills: ['Java', 'Python', 'C++'], + contact: { + email: 'jane@example.com', + phone: '123-456-7891' + }, + active: false + }, + { + id: 3, + name: 'Bob Johnson', + position: 'Graphic Designer', + skills: ['Adobe Photoshop', 'Illustrator', 'InDesign'], + contact: { + email: 'bob@example.com', + phone: '123-456-7892' + }, + active: true + }, + { + id: 4, + name: 'Alice Williams', + position: 'Marketing Coordinator', + skills: ['communication', 'content creation', 'event planning'], + contact: { + email: 'alice@example.com', + phone: '123-456-7893' + }, + active: true + } +]) +``` + +## $all + +_Syntax_: `{ : { $all: [ , , ... ] } }` + +Use the `$all` operator when you want to select documents that contain every single element in a specified array. + +:::note +When using an `$all` operator, the order of the elements and array size does not matter, as long as the array contains all the elements in the query. +::: + +**Example:** Find all documents in the `team` collection where the `skills` field contains both `communication` and `content creation` as elements using the following query operation: + +```js +db.team.find({ + skills: { + $all: ['communication', 'content creation'] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a5bb4acf72d6203bb45bb5"), + id: 4, + name: 'Alice Williams', + position: 'Marketing Coordinator', + skills: ['communication', 'content creation', 'event planning'], + contact: { email: 'alice@example.com', phone: '123-456-7893' }, + active: true + } +] +``` + +## $elemMatch + +_Syntax_: `{ : { $elemMatch: { , , ... } } }` + +To select documents in a specified array field where one or more elements match all listed query conditions, use the `$elemMatch` operator. + +**Example:** Find documents in the `team` collection where the `skills` field is an array that contains the element "Java", and array does not contain the element `communication`. +Use the following query operation: + +```js +db.team.find({ + skills: { + $elemMatch: { + $eq: 'Java', + $nin: ['communication'] + } + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63aa247e69c82de72bd40b93"), + id: 2, + name: 'Jane Mark', + position: 'Software Developer', + skills: ['Java', 'Python', 'C++'], + contact: { email: 'jane@example.com', phone: '123-456-7891' }, + active: false + } +] +``` + +## $size + +_Syntax_: `{ : { $size: } }` + +The `$size` operator is ideal for selecting array fields containing a specified number of elements. + +**Example:** Select the documents in the `team` collection where the `skills` array contains only three elements. + +```js +db.team.find({ + skills: { + $size: 3 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63aa247e69c82de72bd40b92"), + id: 1, + name: 'Jack Smith', + position: 'Manager', + skills: ['leadership', 'communication', 'project management'], + contact: { email: 'john@example.com', phone: '123-456-7890' }, + active: true + }, + { + _id: ObjectId("63aa247e69c82de72bd40b93"), + id: 2, + name: 'Jane Mark', + position: 'Software Developer', + skills: ['Java', 'Python', 'C++'], + contact: { email: 'jane@example.com', phone: '123-456-7891' }, + active: false + }, + { + _id: ObjectId("63aa247e69c82de72bd40b94"), + id: 3, + name: 'Bob Johnson', + position: 'Graphic Designer', + skills: ['Adobe Photoshop', 'Illustrator', 'InDesign'], + contact: { email: 'bob@example.com', phone: '123-456-7892' }, + active: true + }, + { + _id: ObjectId("63aa247e69c82de72bd40b95"), + id: 4, + name: 'Alice Williams', + position: 'Marketing Coordinator', + skills: ['communication', 'content creation', 'event planning'], + contact: { email: 'alice@example.com', phone: '123-456-7893' }, + active: true + } +] +``` diff --git a/website/versioned_docs/version-v1.15/operators/query/bitwise-operators.md b/website/versioned_docs/version-v1.15/operators/query/bitwise-operators.md new file mode 100644 index 000000000000..14a01d1756f5 --- /dev/null +++ b/website/versioned_docs/version-v1.15/operators/query/bitwise-operators.md @@ -0,0 +1,159 @@ +--- +sidebar_position: 1 +--- + +# Bitwise query operators + +Bitwise query operators help to select documents by evaluating query conditions according to the location of bits. + +| Operator | Description | +| -------------------------------- | ---------------------------------------------------------- | +| [`$bitsAllClear`](#bitsallclear) | Selects documents with clear bit locations (0) | +| [`$bitsAllSet`](#bitsallset) | Selects documents with set bit locations (1) | +| [`$bitsAnyClear`](#bitsanyclear) | Selects documents with at least one clear bit location (0) | +| [`$bitsAnySet`](#bitsanyset) | Selects documents with at least one set bit location (1) | + +For the examples in this section, insert the following documents into the `numbers` collection: + +```js +db.numbers.insertMany([ + { _id: 1, value: 23, binaryValue: '10111' }, + { _id: 2, value: 56, binaryValue: '111000' }, + { _id: 3, value: 67, binaryValue: '1000011' }, + { _id: 4, value: 102, binaryValue: '1100110' }, + { _id: 5, value: 5, binaryValue: '101' } +]) +``` + +## $bitsAllClear + +_Syntax_: `{ : { $bitsAllClear: } }` + +Use the `$bitsAllClear` operator to select documents where the specified bitmask locations in the query are clear (0). + +:::tip +The bitmask can either be a numeric or BinData value. +A BinData value is a BSON type that represents a binary value. +The position of the bits is read from right to left with the rightmost position being `0`. +::: + +**Example:** The following query returns documents in which the `value` field has the second and third bit (position `1` and position `2`) from the right as clear (0). + +```js +db.numbers.find({ + value: { + $bitsAllClear: 6 + } +}) +``` + +The binary representation for `6` in this query is `110`. +The query can also be written to show the positions of the bits to be checked: + +```js +db.numbers.find({ + value: { + $bitsAllClear: [1, 2] + } +}) +``` + +The output: + +```json5 +[{ _id: 2, value: 56, binaryValue: '111000' }] +``` + +For the same query above, the bitmask can also be written as a BinData value: + +```js +db.numbers.find({ + value: { + $bitsAllClear: BinData(0, 'Bg==') + } +}) +``` + +## $bitsAllSet + +_Syntax_: `{ : { $bitsAllSet: } }` + +To select documents where the bitmask locations in a query are set (1), use the `$bitsAllSet` operator. + +**Example:** The following query returns all the documents with positions `1` and positions `2` as set (1): + +```js +db.numbers.find({ + value: { + $bitsAllSet: [1, 2] + } +}) +``` + +The output: + +```json5 +[ + { _id: 1, value: 23, binaryValue: '10111' }, + { _id: 4, value: 102, binaryValue: '1100110' } +] +``` + +See the [$bitsAllClear query operator](#bitsallclear) section for more usage examples. + +## $bitsAnyClear + +_Syntax_: `{ : { $bitsAnyClear: } }` + +Use the `$bitsAnyClear` operator to select documents where at least one of the bitmask locations in the query is clear (0). + +**Example:** The following query returns all the documents with positions `0` and positions `2` as clear (0): + +```js +db.numbers.find({ + value: { + $bitsAnyClear: [0, 2] + } +}) +``` + +The output: + +```json5 +[ + { _id: 2, value: 56, binaryValue: '111000' }, + { _id: 3, value: 67, binaryValue: '1000011' }, + { _id: 4, value: 102, binaryValue: '1100110' } +] +``` + +See the [$bitsAllClear query operator](#bitsallclear) section for more usage examples. + +## $bitsAnySet + +_Syntax_: `{ : { $bitsAnySet: } }` + +The `$bitsAnySet` operator selects documents where at least one of the bitmask locations in the query is set (1). + +**Example:** The following query returns all the documents with positions `0` and positions `2` as set (1): + +```js +db.numbers.find({ + value: { + $bitsAnySet: [0, 2] + } +}) +``` + +The output: + +```json5 +[ + { _id: 1, value: 23, binaryValue: '10111' }, + { _id: 3, value: 67, binaryValue: '1000011' }, + { _id: 4, value: 102, binaryValue: '1100110' }, + { _id: 5, value: 5, binaryValue: '101' } +] +``` + +See the [$bitsAllClear query operator](#bitsallclear) section for more usage examples. diff --git a/website/versioned_docs/version-v1.15/operators/query/comparison-operators.md b/website/versioned_docs/version-v1.15/operators/query/comparison-operators.md new file mode 100644 index 000000000000..e4033deffece --- /dev/null +++ b/website/versioned_docs/version-v1.15/operators/query/comparison-operators.md @@ -0,0 +1,383 @@ +--- +sidebar_position: 1 +--- + +# Comparison query operators + +Comparison query operators allow you to compare the elements in a document to a given query value. + +Go to the comparison query operators: + +| Operator | Description | +| -------------- | ------------------------------------------------------------------------- | +| [`$eq`](#eq) | Selects documents with elements that are equal to a given query value | +| [`$gt`](#gt) | Selects documents with elements that are greater than a given query value | +| [`$gte`](#gte) | Selects documents greater than or equal to specified query | +| [`$lt`](#lt) | Selects documents with elements that are less than a given query value | +| [`$lte`](#lte) | Selects documents with elements less than or equal to given query value | +| [`$in`](#in) | Selects documents that contain the elements in a given array query | +| [`$ne`](#ne) | Selects documents with elements that are not equal to given query value | +| [`$nin`](#nin) | Selects documents that do not contain the elements in a given array query | + +For the examples in this section, insert the following documents into the `employees` collection: + +```js +db.employees.insertMany([ + { + name: { + first: 'Earl', + last: 'Thomas' + }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + name: { + first: 'Sam', + last: 'Johnson' + }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + name: { + first: 'Clarke', + last: 'Dane' + }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +]) +``` + +## $eq + +_Syntax_: `{ : { $eq: } }` + +To select documents that exactly match a given query value, use the `$eq` operator. + +This operator can be used to match values of different types, including documents, array, embedded documents, etc. + +**Example:** The following operation queries the `employees` collection for all documents where the field `age` equals `21`. + +```js +db.employees.find({ + age: { + $eq: 21 + } +}) +``` + +The response returns a single document that matches the query: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +**Example:** To query values in an embedded document, use [dot notation](../../understanding-ferretdb.md#dot-notation). +The following operation queries the `employees` collection for documents that match the field `first` in the embedded document `name`. + +```js +db.employees.find({ + 'name.first': { + $eq: 'Earl' + } +}) +``` + +The response returns a single document that matches the query: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + } +] +``` + +## $gt + +_Syntax_: `{ : { $gt: } }` + +To identify documents containing elements that have a greater value than the specified one in the query, use the `$gt` operator. + +**Example:** Use the following operation to query for all the documents in the `employees` collection where the field `age` is greater than `21`. + +```js +db.employees.find({ + age: { + $gt: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + } +] +``` + +## $gte + +_Syntax_: `{ : { $gte: } }` + +Use the `$gte` to select document with elements that are greater than or equal to a specified value. + +**Example:** The following operation selects documents based on the specified query, where the field `age` is greater than or equal to `21`. + +```js +db.employees.find({ + age: { + $gte: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $lt + +_Syntax_: `{ : { $lt: } }` + +Contrary to the `$gt` operator, the `$lt` operator is ideal for selecting documents with elements that are of a lesser value than that of the specified query. + +**Example:** The following operation queries for documents where the field `age` is less than `25`. + +```js +db.employees.find({ + age: { + $lt: 25 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $lte + +_Syntax_: `{ : { $lte: } }` + +The `$lte` operator is the opposite of the `$gte` operator. +Use the `$lte` operator to select documents with elements that are less than or equal to the specified query value. + +**Example:** The following operation queries for documents where the field `age` is less than or equal to `21`. + +```js +db.employees.find({ + age: { + $lte: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $in + +_Syntax_: `{ : { $in: [, , ... ] } }` + +To select documents containing any of the listed elements in a specified array field, use the `$in` operator. + +**Example:** The following operation queries the `employees` collection for documents where the value of the field `age` is either `21` or `35`. + +```js +db.employees.find({ + age: { + $in: [21, 35] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $ne + +_Syntax_: `{ : { $ne: } }` + +Use the `$ne` operator to select all the documents with elements that are not equal to a given query. + +**Example:** The following operation queries the `employees` collection for documents where the field `age` is not equal to `21`. + +```js +db.employees.find({ + age: { + $ne: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + } +] +``` + +## $nin + +_Syntax_: `{ : { $nin: [ , ... ] } }` + +The `$nin` does exactly the opposite of the `$in` operator. +Use the `$nin` operator when selecting documents that do match or contain any of the elements listed in an array query. + +**Example:** The following operation queries the `employees` collection for documents where the value of the field `age` is not `21` or `35`. + +```js +db.employees.find({ + age: { + $nin: [21, 35] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + } +] +``` diff --git a/website/versioned_docs/version-v1.15/operators/query/element-operators.md b/website/versioned_docs/version-v1.15/operators/query/element-operators.md new file mode 100644 index 000000000000..c18d1f105a15 --- /dev/null +++ b/website/versioned_docs/version-v1.15/operators/query/element-operators.md @@ -0,0 +1,363 @@ +--- +sidebar_position: 4 +--- + +# Element query operators + +Element query operators return data based on the existence of a specified field or the data type of a particular value. + +| Operator | Description | +| -------------------- | ------------------------------------------------------------ | +| [`$exists`](#exists) | returns documents where a field exists or does not exist | +| [`$type`](#type) | matches document containing elements with the specified type | + +For the examples in this section, insert the following documents into the `electronics` collection: + +```js +db.electronics.insertMany([ + { + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [ + { + processor: 'Intel Core i7' + }, + { + memory: 16 + } + ] + }, + { + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [ + { + brand: 'Apple' + }, + { + model: 'iPhone 12' + } + ] + }, + { + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [ + { + brand: 'Samsung' + }, + { + model: 'Galaxy Tab S7' + } + ] + }, + { + product: 'keyboard', + price: 100, + stock: 20 + }, + { + product: 'mouse', + price: 50, + stock: 25, + discount: null, + specifications: [] + }, + { + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [ + { + size: 27 + }, + { + resolution: '4K' + } + ] + }, + { + product: 'printer', + price: 150, + stock: 35, + discount: false + }, + { + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [ + { + type: 'flatbed' + } + ] + } +]) +``` + +## $exists + +_Syntax_: `{ : { $exists: } }` + +To find out if a particular field exists in a document, use the `$exists` operator. + +:::tip +If the `` value is `true`, the query returns documents where the specified field exists, even if the value is `null` or an empty array. +If the `` value is `false`, the query returns documents where the specified field does not exist. +::: + +**Example:** Find documents in the `electronics` collection where the `specifications` field exists using the `$exists` operator: + +```js +db.electronics.find({ + specifications: { + $exists: true + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a32fc7cf72d6203bb45b8e"), + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [{ processor: 'Intel Core i7' }, { memory: 16 }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b8f"), + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [{ brand: 'Apple' }, { model: 'iPhone 12' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b90"), + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [{ brand: 'Samsung' }, { model: 'Galaxy Tab S7' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b92"), + product: 'mouse', + price: 50, + stock: 25, + discount: null, + specifications: [] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b93"), + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [{ size: 27 }, { resolution: '4K' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b95"), + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [{ type: 'flatbed' }] + } +] +``` + +In the above output, the query returns all documents where the `specifications` field exists, even when the `field` has an empty value. + +If you want to find documents where the `specifications` field exists and has a specific value, use the `$exists` operator in conjunction with other operators. + +**Example:** The following query returns all documents where the `specifications` field exists and its value is an array: + +```js +db.electronics.find({ + specifications: { + $exists: true, + $type: 'array' + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a32fc7cf72d6203bb45b8e"), + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [{ processor: 'Intel Core i7' }, { memory: 16 }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b8f"), + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [{ brand: 'Apple' }, { model: 'iPhone 12' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b90"), + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [{ brand: 'Samsung' }, { model: 'Galaxy Tab S7' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b92"), + product: 'mouse', + price: 50, + stock: 25, + discount: null, + specifications: [] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b93"), + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [{ size: 27 }, { resolution: '4K' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b95"), + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [{ type: 'flatbed' }] + } +] +``` + +## $type + +_Syntax_: `{ : { $type: } }` + +Use the `$type` operator to select documents where the data type of a field matches the specified BSON type + +The `` parameter can be the type code or alias of the particular data type. + +The following table lists the available BSON type codes and their corresponding aliases: + +| Type code | Type | Alias | +| --------- | ------------------ | --------- | +| 1 | Double | double | +| 2 | String | string | +| 3 | Object | object | +| 4 | Array | array | +| 5 | Binary data | binData | +| 7 | ObjectId | objectId | +| 8 | Boolean | bool | +| 9 | Date | date | +| 10 | Null | null | +| 11 | Regular expression | regex | +| 16 | 32-bit integer | int | +| 17 | Timestamp | timestamp | +| 18 | 64-bit integer | long | +| 19 | Decimal128 | decimal | +| -1 | Min key | minKey | +| 127 | Max key | maxKey | +| -128 | Number | number | + +:::caution +`Decimal128`, `Min Key`, and `Max Key` are not currently implemented. +FerretDB supports the alias `number` which matches the following BSON types: `Double`, `32-bit integer`, and `64-bit integer` type values. +::: + +:::info +FerretDB supports the alias `number` which matches the following BSON types: `Double`, `32-bit integer`, and `64-bit integer` type values. +::: + +**Example:** The following operation query returns all documents in the `electronics` collection where the `discount` field has a boolean data type, which can be represented with the data code `8`: + +```js +db.electronics.find({ + discount: { + $type: 8 + } +}) +``` + +This query can also be written using the alias of the specified data type. + +```js +db.electronics.find({ + discount: { + $type: 'bool' + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a32fc7cf72d6203bb45b8e"), + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [{ processor: 'Intel Core i7' }, { memory: 16 }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b8f"), + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [{ brand: 'Apple' }, { model: 'iPhone 12' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b90"), + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [{ brand: 'Samsung' }, { model: 'Galaxy Tab S7' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b93"), + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [{ size: 27 }, { resolution: '4K' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b94"), + product: 'printer', + price: 150, + stock: 35, + discount: false + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b95"), + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [{ type: 'flatbed' }] + } +] +``` diff --git a/website/versioned_docs/version-v1.15/operators/query/evaluation-operators.md b/website/versioned_docs/version-v1.15/operators/query/evaluation-operators.md new file mode 100644 index 000000000000..3a6b046ecaf0 --- /dev/null +++ b/website/versioned_docs/version-v1.15/operators/query/evaluation-operators.md @@ -0,0 +1,164 @@ +--- +sidebar_position: 5 +--- + +# Evaluation query operators + +Evaluation query operators return data based on the evaluation of a specified expression. + +| Operator | Description | +| ------------------ | ----------------------------------------------------------------------------------------------------------------- | +| [`$mod`](#mod) | Matches documents where the field element is divided by a given value and returns a the specified remainder value | +| [`$regex`](#regex) | Matches documents where a field matches a specified regular expression query | + +For the examples in this section, insert the following documents into the `catalog` collection: + +```js +db.catalog.insertMany([ + { + product: 'bottle', + price: 15, + stock: 1 + }, + { + product: 'spoon', + price: 500, + stock: 0 + }, + { + product: 'cup', + price: 100, + stock: 14 + }, + { + product: 'BoWL', + price: 56, + stock: 5 + }, + { + product: 'boTtLe', + price: 20, + stock: 3 + } +]) +``` + +## $mod + +_Syntax_: `{ : { $mod: [ , ] } }` + +The `$mod` operator matches documents where the field element divided by a given value returns a specified remainder (otherwise known as a modulus). +The mathematical operation for this is `field-value % divisor-value = modulus`. + +**Example:** The following query returns all the documents where the value of the "stock" field is evenly divisible by 2: + +```js +db.catalog.find({ + stock: { + $mod: [2, 0] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63e3ac0184f488929a3f737a"), + product: 'spoon', + price: 500, + stock: 0 + }, + { + _id: ObjectId("63e3ac0184f488929a3f737b"), + product: 'cup', + price: 100, + stock: 14 + } +] +``` + +:::caution +Note that the `$mod` expression returns an error if you only have a single element in the array, more than two elements in the array, or if the array is empty. +It also rounds down decimal input down to zero (e.g. `$mod: [ 3.5 , 2 ]` is executed as `$mod: [ 3 , 2 ]`). +::: + +## $regex + +_Syntax_: `{ : { $regex: '', $options: '' } }` + +Other syntaxes: `{ : { $regex: //, $options: '' } }` and `{ : // }`. + +To use regular expression for queries on particular fields, use the `$regex` operator. + +**Example:** The following query returns all the documents where the value of the "product" field starts with the letter "b": + +```js +db.catalog.find({ + product: { + $regex: /^b/ + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63e4ce469695494b86bf2b2d"), + product: 'bottle', + price: 15, + stock: 1 + }, + { + _id: ObjectId("63e4ce469695494b86bf2b31"), + product: 'boTtLe', + price: 20, + stock: 3 + } +] +``` + +`$options` is an optional parameter that specifies the regular expression flags to use, such as: + +- Case-insensitivity (`i`) +- Multi-line matching (`m`) +- Dot character matching (`s`) + +:::note +The regex flag for ignoring white spaces (`x`) is not currently supported. +Follow [here](https://github.com/FerretDB/FerretDB/issues/592) for more updates. +::: + +To perform case-insensitive matching, use the `i` flag in the `regex` expression. + +**Example:** The following query returns all the documents where the value of the "product" field is equal to "bottle" (case-insensitive): + +```js +db.catalog.find({ + product: { + $regex: /bottle/i + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63e3ac0184f488929a3f7379"), + product: 'bottle', + price: 15, + stock: 1 + }, + { + _id: ObjectId("63e3ac0184f488929a3f737d"), + product: 'boTtLe', + price: 20, + stock: 3 + } +] +``` diff --git a/website/versioned_docs/version-v1.15/operators/query/logical-operators.md b/website/versioned_docs/version-v1.15/operators/query/logical-operators.md new file mode 100644 index 000000000000..aec278a1fb05 --- /dev/null +++ b/website/versioned_docs/version-v1.15/operators/query/logical-operators.md @@ -0,0 +1,309 @@ +--- +sidebar_position: 2 +--- + +# Logical query operators + +Logical query operators return data based on specified query expressions that are either true or false. + +| Operator | Description | +| -------------- | -------------------------------------------------------------------- | +| [`$and`](#and) | Joins all query expressions with a logical AND operator | +| [`$or`](#or) | Joins all query expressions with a logical OR operator | +| [`$not`](#not) | Returns all documents that do NOT match a query expression | +| [`$nor`](#nor) | Returns all documents that do not match any of the query expressions | + +For the examples in this section, insert the following documents into the `catalog` collection: + +```js +db.catalog.insertMany([ + { + product: 'bottle', + price: 15, + stock: 1, + discount: true, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['black', 'silver'] + } + ] + }, + { + product: 'spoon', + price: 500, + stock: 0, + discount: true, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['silver', 'white'] + } + ] + }, + { + product: 'cup', + price: 100, + stock: 14, + discount: true, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['red', 'black', 'white'] + } + ] + }, + { + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['pink', 'white', 'red'] + } + ] + } +]) +``` + +## $and + +_Syntax_: `{ $and: [ { }, { } , ... , { } ] }` + +To satisfy more than one query condition when selecting documents, use the `$and` operator. + +**Example:** Select documents that satisfy both of these expressions in the `catalog` collection: + +- `price` field is less than `100` **AND** +- `stock` field is not `0` + +```js +db.catalog.find({ + $and: [ + { + price: { + $lt: 100 + } + }, + { + stock: { + $ne: 0 + } + } + ] +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f13"), + product: 'bottle', + price: 15, + stock: 1, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['black', 'silver'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f16"), + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['pink', 'white', 'red'] } + ] + } +] +``` + +## $or + +_Syntax_: `{ $or: [ { }, { } , ... , { } ] }` + +To satisfy either one or more conditions in a query, use the `$or` operator to join the conditions. + +**Example:** Select the documents that match these expressions: + +- `discount` field is `true` _and_ `stock` field is not `0` **OR** +- `price` field is less than or equal to `60` + +```js +db.catalog.find({ + $or: [ + { + $and: [ + { + discount: true + }, + { + stock: { + $ne: 0 + } + } + ] + }, + { + price: { + $lte: 60 + } + } + ] +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f13"), + product: 'bottle', + price: 15, + stock: 1, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['black', 'silver'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f15"), + product: 'cup', + price: 100, + stock: 14, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['red', 'black', 'white'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f16"), + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['pink', 'white', 'red'] } + ] + } +] +``` + +## $not + +_Syntax_: `{ : { $not: { } } }` + +To select documents that fail to match a particular query condition, use the `$not` operator. + +**Example:** The following operation selects documents that do not satisfy the specified expression, where the `stock` field is not less than `5`. + +```js +db.catalog.find({ + stock: { + $not: { + $lt: 5 + } + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f15"), + product: 'cup', + price: 100, + stock: 14, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['red', 'black', 'white'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f16"), + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['pink', 'white', 'red'] } + ] + } +] +``` + +## $nor + +_Syntax_: `{ $nor: [ { }, { }, ... { } ] }` + +To select documents that fail to match any of the conditions in a specified query, use the `$nor` operator. + +**Example:** Select the documents that fail to match any of these conditions: + +- `discount` field is `true` _and_ `stock` field is not `0` +- `price` field is less than or equal to `60` + +```js +db.catalog.find({ + $nor: [ + { + $and: [ + { + discount: true + }, + { + stock: { + $ne: 0 + } + } + ] + }, + { + price: { + $lte: 60 + } + } + ] +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f14"), + product: 'spoon', + price: 500, + stock: 0, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['silver', 'white'] } + ] + } +] +``` diff --git a/website/versioned_docs/version-v1.15/operators/update/_category_.yml b/website/versioned_docs/version-v1.15/operators/update/_category_.yml new file mode 100644 index 000000000000..192683635dc2 --- /dev/null +++ b/website/versioned_docs/version-v1.15/operators/update/_category_.yml @@ -0,0 +1,9 @@ +--- +label: Update Operators +position: 2 +link: + type: generated-index + slug: /update/ + description: > + The section contains all the different types of update operators available + on FerretDB diff --git a/website/versioned_docs/version-v1.15/operators/update/array-update-operators.md b/website/versioned_docs/version-v1.15/operators/update/array-update-operators.md new file mode 100644 index 000000000000..6c7c6df4bad7 --- /dev/null +++ b/website/versioned_docs/version-v1.15/operators/update/array-update-operators.md @@ -0,0 +1,215 @@ +--- +sidebar_position: 1 +--- + +# Array update operators + +Array update operators allow you to modify the elements of an array field in a document. + +| Operator | Description | +| ------------------------ | -------------------------------------------------------------------------------------------- | +| [`$push`](#push) | Adds an element to an array | +| [`$addToSet`](#addtoset) | Adds elements to a specific array as long as the element does not already exist in the array | +| [`$pop`](#pop) | Removes either the first or the last element of an array | +| [`$pullAll`](#pullall) | Removes all matching values in a specified query from an array | + +## $push + +The `$push` operator updates a document by adding an element to a specified array. +If the array does not exist, a new array is created with the element added to it. + +Insert the following document into a `store` collection: + +```js +db.store.insertMany([ + { _id: 1, items: ['pens', 'pencils', 'paper', 'erasers', 'rulers'] } +]) +``` + +**Example:** Use the `$push` operator to add an element to an existing array. + +```js +db.store.updateOne({ _id: 1 }, { $push: { items: 'markers' } }) +``` + +After the operation, the updated document looks like this: + +```json5 +[ + { + _id: 1, + items: ['pens', 'pencils', 'paper', 'erasers', 'rulers', 'markers'] + } +] +``` + +## $addToSet + +The `$addToSet` operator updates an array by adding a specified element to an array if the element does not already exist in the array. +If the specified element exists in the array, the `$addToSet` operator will not modify the array. + +Insert the following documents into a `store` collection: + +```js +db.store.insertMany([{ _id: 1, items: ['pens', 'pencils'] }]) +``` + +**Example:** Use the `$addToSet` operator to update the array with non-existing elements. + +```js +db.store.updateOne({ _id: 1 }, { $addToSet: { items: 'paper' } }) +``` + +The document is subsequently updated with the new element, as depicted below: + +```json5 +[{ _id: 1, items: ['pens', 'pencils', 'paper'] }] +``` + +**Example:** Use the `$addToSet` operator to update the array with already existing elements. + +```js +db.store.updateOne({ _id: 1 }, { $addToSet: { items: 'pens' } }) +``` + +Since the array already contains the element, there won't be any changes. + +```json5 +[{ _id: 1, items: ['pens', 'pencils', 'paper'] }] +``` + +:::note +The `$addToSet` is different from the `$push` operator which adds the element to the array either it exists or not. +::: + +**Example:** Use the `$addToSet` operator for non-existing array fields. + +If the array field does not exist in the document, the `$addToSet` operator will create the field and add the element to the array. + +```js +db.store.updateOne({ _id: 1 }, { $addToSet: { colors: 'red' } }) +``` + +The updated document looks like this: + +```json5 +[{ _id: 1, items: ['pens', 'pencils', 'paper'], colors: ['red'] }] +``` + +## $pop + +With the `$pop` operator, you can update a document by removing the first or last element of an array. +Assign a value of `-1` to remove the first element of an array, or `1` to remove the last element. + +Insert this document into a `products` collection: + +```js +db.products.insertMany([ + { _id: 1, items: ['pens', 'pencils', 'paper', 'erasers', 'rulers'] } +]) +``` + +**Example:** Use the `$pop` operator to remove the first element of an array. + +```js +db.products.updateOne({ _id: 1 }, { $pop: { items: -1 } }) +``` + +The document is subsequently updated with the first element `pens` removed, as depicted below: + +```json5 +[ + { + _id: 1, + items: ['pencils', 'paper', 'erasers', 'rulers'] + } +] +``` + +To remove the last element of the array, assign `1` as the value for the `$pop` operator. + +```js +db.products.updateOne({ _id: 1 }, { $pop: { items: 1 } }) +``` + +The updated now looks like this: + +```json5 +[ + { + _id: 1, + items: ['pencils', 'paper', 'erasers'] + } +] +``` + +## $pullAll + +The `$pullAll` operator removes all the matching elements in a specified query from an array. + +Insert the following document into a `store` collection: + +```js +db.store.insertMany([ + { _id: 1, items: ['pens', 'pencils', 'paper', 'erasers', 'rulers'] } +]) +``` + +**Example:** Use the `$pullAll` operator to remove multiple elements from an array. + +```js +db.store.updateOne( + { _id: 1 }, + { $pullAll: { items: ['pens', 'pencils', 'paper'] } } +) +``` + +After removing all instances of the specified array elements, the document is updated as follows: + +```json5 +[ + { + _id: 1, + items: ['erasers', 'rulers'] + } +] +``` + +**Example:** Use the `$pullAll` operator to remove array of objects from an array. + +Insert the following document into a `fruits` collection: + +```js +db.fruits.insertMany([ + { + _id: 1, + fruits: [ + { type: 'apple', color: 'red' }, + { type: 'banana', color: 'yellow' }, + { type: 'orange', color: 'orange' } + ] + } +]) +``` + +The following query uses the `$pullAll` to remove all matching array objects from the specified document. + +```js +db.fruits.update( + { _id: 1 }, + { + $pullAll: { + fruits: [ + { type: 'apple', color: 'red' }, + { type: 'banana', color: 'yellow' } + ] + } + } +) +``` + +The updated document now looks like this: + +```json5 +[{ _id: 1, fruits: [{ type: 'orange', color: 'orange' }] }] +``` diff --git a/website/versioned_docs/version-v1.15/operators/update/field-update-operators.md b/website/versioned_docs/version-v1.15/operators/update/field-update-operators.md new file mode 100644 index 000000000000..303615272247 --- /dev/null +++ b/website/versioned_docs/version-v1.15/operators/update/field-update-operators.md @@ -0,0 +1,370 @@ +--- +sidebar_position: 1 +--- + +# Field update operators + +Field update operators allow you to modify the value of a specified field in a document when certain conditions are met. + +| Operator | Description | +| ------------------------------ | ------------------------------------------------------------------------------------------- | +| [`$set`](#set) | Assigns the value of a given field | +| [`$unset`](#unset) | Deletes the records of a field from a document | +| [`$inc`](#inc) | Increments a given field's value | +| [`$mul`](#mul) | Multiplies a given field's value by a specific value | +| [`$rename`](#rename) | Renames a given field with another name | +| [`$min`](#min) | Updates a particular field only when the specified value is lesser than the specified value | +| [`$max`](#max) | Updates a particular field only when the specified value is higher than the specified value | +| [`$currentDate`](#currentdate) | Specifies the current date and time as the value of a given field | +| [`$setOnInsert`](#setoninsert) | Inserts elements into an array only if they don't already exist | + +For the examples in this section, insert the following documents into the `employees` collection: + +```js +db.employee.insertOne({ + name: 'John Doe', + age: 35, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'Anytown', + state: 'CA' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: new Date('2021-01-01'), + endDate: null +}) +``` + +## $set + +The `$set` operator updates the value of a specified field and if the field does not exist, the `$set` operator creates a new field and adds it to the document. + +**Example:** The below query is an example that updates the value of the `city` field in the `address` embedded document. + +```js +db.employee.updateOne( + { name: 'John Doe' }, + { + $set: { + 'address.city': 'New York', + 'address.zip': '12345' + } + } +) +``` + +The above query updates the value of the `city` field in the `address` embedded document and adds a new field `zip` to it. + +This is the updated document: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 35, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA', + zip: '12345' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $unset + +The `$unset` operator deletes the specified field from a document and if the field is not present, the `$unset` operator will not do anything. + +**Example:** The below query deletes the `zip` field from the embedded document `address`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $unset: { 'address.zip': '' } }) +``` + +Below is the updated document, without the `zip` field: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 35, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $inc + +The `$inc` operator increments the value of a given field by a specified amount. +If the field is non-existent in the document, the `$inc` operator creates a new field and adds it to the document, setting the value to the specified increment amount. + +**Example:** The below query increments the value of the `age` field by `1`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $inc: { age: 1 } }) +``` + +The updated document looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 36, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $mul + +The `$mul` operator multiplies the value of a given field by a specified amount. +Similar to all most of the other field update operators, if the field is non-existent in the document, the `$mul` operator creates a new one and sets the value to `0`. + +**Example:** This example query multiplies the value of the `salary` field by `25%`, represented as `1.25`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $mul: { salary: 1.25 } }) +``` + +The updated record looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 36, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $rename + +The `$rename` operator renames a given field to another name. + +**Example:** The query below updates the `employee` collection and renames the `jobTitle` field to `title`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $rename: { jobTitle: 'title' } }) +``` + +The updated document looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 36, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null, + title: 'Manager' + } +] +``` + +## $min + +The `$min` operator compares a specified value with the value of the given field and updates the field to the specified value if the specified value is less than the current value of the field. + +**Example:** The below query updates the value of the `age` field to `30` as long as the current value is less than `30`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $min: { age: 30 } }) +``` + +Since `30` is less than `36`, the value of the `age` field is updated to `30`. +The updated document now looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 30, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null, + title: 'Manager' + } +] +``` + +## $max + +The `$max` operator compares a specified value with the value of the given field and updates the field to the specified value if the specified value is greater than the current value of the field. + +**Example:** The below query updates the value of the `age` field to `40` as long as the current value is greater than `40`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $max: { age: 40 } }) +``` + +This is what the updated document looks like: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 40, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { street: '123 Main St', city: 'New York', state: 'CA' }, + salary: 62500, + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null, + height: 0, + title: 'Manager' + } +] +``` + +## $currentDate + +The `$currentDate` operator assigns the current date as the value of a given field. +This can be as a date or timestamp. + +**Example:** To update the `startDate` field with the current date, use the following query: + +```js +db.employee.updateOne( + { name: 'John Doe' }, + { $currentDate: { startDate: true } } +) +``` + +This is the document after the update: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 40, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + startDate: ISODate('2023-03-10T01:26:35.606Z'), + endDate: null, + height: 0, + title: 'Manager' + } +] +``` + +## $setOnInsert + +The `$setOnInsert` operator sets the value of a given field if the document is inserted into a collection during an upsert operation. +If there is no insertion, the `$setOnInsert` operator does nothing. + +**Example:** Let's say you have a `stocks` collection that stores information about different stocks, and you want to update the stock information or add a new stock if it doesn't exist. +Here's an example of how `$SetOnInsert` works differently from `$set`. + +Using `$set`: + +```js +db.stocks.update( + { symbol: 'AAPL' }, + { + $set: { + price: 150, + lastUpdate: new Date() + } + }, + { upsert: true } +) +``` + +This query checks for a stock with the symbol "AAPL". +If it finds the stock, it updates the `price` and `lastUpdate` fields. +If it doesn't find the stock, it inserts a new document with the `symbol`, `price`, and `lastUpdate` fields. + +Using `$setOnInsert`: + +```js +db.stocks.update( + { symbol: 'AAPL' }, + { + $set: { price: 150 }, + $setOnInsert: { + companyName: 'Apple Inc.', + createdAt: new Date() + } + }, + { upsert: true } +) +``` + +This query also checks for a stock with the symbol "AAPL". +If it finds the stock, it updates only the `price` field. +If it doesn't find the stock, it inserts a new document with the `symbol`, `price`, `companyName`, and `createdAt` fields. +The `companyName` and `createdAt` fields are only added when a new document is inserted. + +Comparing both examples, the `$set` operator updates or inserts the specified fields in both cases. +On the other hand, the `$setOnInsert` operator sets the specified fields only when a new document is inserted, leaving existing documents unchanged. diff --git a/website/versioned_docs/version-v1.15/pushdown.md b/website/versioned_docs/version-v1.15/pushdown.md new file mode 100644 index 000000000000..c6f0f228cfcf --- /dev/null +++ b/website/versioned_docs/version-v1.15/pushdown.md @@ -0,0 +1,54 @@ +--- +sidebar_position: 7 +hide_table_of_contents: true +--- + +# Query pushdown + +**Query pushdown** is the method of optimizing a query by reducing the amount of data read and processed. +It saves memory space, network bandwidth, and reduces the query execution time by moving some parts +of the query execution closer to the data source. + +Initially FerretDB retrieved all data related to queried collection, and applies filters on its own, making +it possible to implement complex logic safely and quickly. +To make this process more efficient, we minimize the amount of incoming data, by applying WHERE clause on SQL queries. + +:::info +You can learn more about query pushdown in our [blog post](https://blog.ferretdb.io/ferretdb-fetches-data-query-pushdown/). +::: + +## Supported types and operators + +The following table shows all operators and types that FerretDB pushdowns on PostgreSQL backend. +If filter uses type and operator, that's marked as pushdown-supported on this list, +FerretDB will prefetch less data, resulting with more performent query. + +If your application requires better performance for specific operation, +feel free to share this with us in our [community](/#community)! + +:::tip +As query pushdown allows developers to implement query optimizations separately from the features, +the table will be updated frequently. +::: + + + + +| | Object | Array | Double | String | Binary | ObjectID | Boolean | Date | Null | Regex | Integer | Timestamp | Long | +| ------ | ------ | ----- | ----------------------- | ------ | ------ | -------- | ------- | ---- | ---- | ----- | ------- | --------- | ----------------------- | +| `=` | ✖️ | ✖️ | ⚠️ [[1]](#1) | ✅ | ✖️ | ✅ | ✅ | ✅ | ✖️ | ✖️ | ✅ | ✖️ | ⚠️ [[1]](#1) | +| `$eq` | ✖️ | ✖️ | ⚠️ [[1]](#1) | ✅ | ✖️ | ✅ | ✅ | ✅ | ✖️ | ✖️ | ✅ | ✖️ | ⚠️ [[1]](#1) | +| `$gt` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$gte` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$lt` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$lte` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$in` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$ne` | ✖️ | ✖️ | ⚠️ [[1]](#1) | ✅ | ✖️ | ✅ | ✅ | ✅ | ✖️ | ✖️ | ✅ | ✖️ | ⚠️ [[1]](#1) | +| `$nin` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | + +###### [1] {#1} + +Numbers outside the range of the safe IEEE 754 precision (`< -9007199254740991.0, 9007199254740991.0 >`), +will prefetch all numbers larger/smaller than max/min value of the range. + + diff --git a/website/versioned_docs/version-v1.15/quickstart-guide/_category_.yml b/website/versioned_docs/version-v1.15/quickstart-guide/_category_.yml new file mode 100644 index 000000000000..ff1c769eb893 --- /dev/null +++ b/website/versioned_docs/version-v1.15/quickstart-guide/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Get Started +position: 3 +link: + type: generated-index + slug: /quickstart-guide/ # referenced in README.md + description: > + Learn to install FerretDB on your local machine diff --git a/website/versioned_docs/version-v1.15/quickstart-guide/deb.md b/website/versioned_docs/version-v1.15/quickstart-guide/deb.md new file mode 100644 index 000000000000..d3c9e4f4c0ba --- /dev/null +++ b/website/versioned_docs/version-v1.15/quickstart-guide/deb.md @@ -0,0 +1,37 @@ +--- +sidebar_position: 2 +--- + +# DEB package + +To install the `.deb` packages for FerretDB on your Debian, Ubuntu, and other `.deb`-based systems, +you can use `dpkg` tool. + +Download the latest FerretDB `.deb` package from [our release pages](https://github.com/FerretDB/FerretDB/releases/latest), +rename it to `ferretdb.deb`, +then run the following command in your terminal: + +```sh +sudo dpkg -i ferretdb.deb +``` + +You can check that FerretDB was installed by running + +```sh +ferretdb --version +``` + +FerretDB does not automatically install PostgreSQL or other backends. +To install PostgreSQL, run the following commands: + +```sh +sudo apt update +sudo apt install -y postgresql +``` + +Currently, our `.deb` package does not provide a SystemD unit for starting FerretDB automatically. +You have to do it manually by running `ferretdb` binary with the [correct flags](../configuration/flags.md). + +Find out more about: + +- [getting logs](../configuration/observability.md#binary-executable-logs). diff --git a/website/versioned_docs/version-v1.15/quickstart-guide/docker.md b/website/versioned_docs/version-v1.15/quickstart-guide/docker.md new file mode 100644 index 000000000000..0a3e0d9323cf --- /dev/null +++ b/website/versioned_docs/version-v1.15/quickstart-guide/docker.md @@ -0,0 +1,138 @@ +--- +sidebar_position: 1 +slug: /quickstart-guide/docker/ # referenced in README.md +description: How to set up FerretDB using Docker +--- + +# Docker + +We provide three Docker images for various deployments: +**"all-in-one"** for quick testing and experiments, +**a development image** for debugging problems, +and **a production image** for all other cases. + +All-in-one image is documented in the +[README.md file in the repository](https://github.com/FerretDB/FerretDB#quickstart). +The rest are covered below. + +## Production image + +Our [production image](https://ghcr.io/ferretdb/ferretdb) `ghcr.io/ferretdb/ferretdb` +is recommended for most deployments. +It does not include PostgreSQL or other backends, so you must run them separately. +You can do that with Docker Compose, Kubernetes, or other means. + +### PostgreSQL Setup with Docker Compose + +The following steps describe a quick local setup: + +1. Store the following in the `docker-compose.yml` file: + + ```yaml + services: + postgres: + image: postgres + environment: + - POSTGRES_USER=username + - POSTGRES_PASSWORD=password + - POSTGRES_DB=ferretdb + volumes: + - ./data:/var/lib/postgresql/data + + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27017:27017 + environment: + - FERRETDB_POSTGRESQL_URL=postgres://postgres:5432/ferretdb + + networks: + default: + name: ferretdb + ``` + + `postgres` container runs PostgreSQL that would store data in the `./data` directory on the host. + `ferretdb` runs FerretDB. + +2. Start services with `docker compose up -d`. +3. If you have `mongosh` installed, just run it to connect to FerretDB. + It will use credentials passed in `mongosh` flags or MongoDB URI to authenticate to the PostgreSQL database. + You'll also need to set `authMechanism` to `PLAIN`. + The example URI would look like: + + ```text + mongodb://username:password@127.0.0.1/ferretdb?authMechanism=PLAIN + ``` + + See [Authentication](../security/authentication.md) and + [Securing connection with TLS](../security/tls-connections.md) for more details. + + If you don't have `mongosh`, run the following command to run it inside the temporary MongoDB container, + attaching to the same Docker network: + + ```sh + docker run --rm -it --network=ferretdb --entrypoint=mongosh mongo \ + "mongodb://username:password@ferretdb/ferretdb?authMechanism=PLAIN" + ``` + +You can improve that setup by: + +- [securing connections with TLS](../security/tls-connections.md); +- adding backups. + +Find out more about: + +- [getting logs](../configuration/observability.md#docker-logs). + +### SQLite Setup with Docker Compose + +The following steps describe the setup for SQLite: + +1. Store the following in the `docker-compose.yml` file: + + ```yaml + services: + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27017:27017 + environment: + - FERRETDB_HANDLER=sqlite + volumes: + - ./state:/state + + networks: + default: + name: ferretdb + ``` + + Unlike PostgreSQL, SQLite operates serverlessly so it does not require its own service in Docker Compose. + :::note + At the moment, authentication is not available for the SQLite backend ([See Issue here](https://github.com/FerretDB/FerretDB/issues/3008)). + ::: + +2. Start services with `docker compose up -d`. +3. If you have `mongosh` installed, just run it to connect to FerretDB. + + The example URI would look like: + + ```text + mongodb://127.0.0.1:27017/ferretdb + ``` + + Similarly, if you don't have `mongosh` installed, run this command to run it inside the temporary MongoDB container, attaching to the same Docker network: + + ```text + docker run --rm -it --network=ferretdb --entrypoint=mongosh mongo \ + "mongodb://ferretdb/ferretdb" + ``` + +## Development image + +The [development image](https://ghcr.io/ferretdb/ferretdb-dev) `ghcr.io/ferretdb/ferretdb-dev` +contains the [debug build](https://pkg.go.dev/github.com/FerretDB/FerretDB/build/version#hdr-Debug_builds) +of FerretDB with test coverage instrumentation, race detector, +and other changes that make it more suitable for debugging problems. +It can be used exactly the same way as the production image, as described above. diff --git a/website/versioned_docs/version-v1.15/quickstart-guide/go.md b/website/versioned_docs/version-v1.15/quickstart-guide/go.md new file mode 100644 index 000000000000..c3a5c313aa29 --- /dev/null +++ b/website/versioned_docs/version-v1.15/quickstart-guide/go.md @@ -0,0 +1,11 @@ +--- +sidebar_position: 6 +--- + +# Go + +See https://pkg.go.dev/github.com/FerretDB/FerretDB/ferretdb. + +_This section is not currently available. +You can help FerretDB by contributing to this section. +Click the **Edit this page** link below to get started_. diff --git a/website/versioned_docs/version-v1.15/quickstart-guide/macos.md b/website/versioned_docs/version-v1.15/quickstart-guide/macos.md new file mode 100644 index 000000000000..8cd14d51dbc4 --- /dev/null +++ b/website/versioned_docs/version-v1.15/quickstart-guide/macos.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 4 +--- + +# macOS + +_This section is not currently available. +You can help FerretDB by contributing to this section. +Click the **Edit this page** link below to get started_. diff --git a/website/versioned_docs/version-v1.15/quickstart-guide/rpm.md b/website/versioned_docs/version-v1.15/quickstart-guide/rpm.md new file mode 100644 index 000000000000..8b7c2918771b --- /dev/null +++ b/website/versioned_docs/version-v1.15/quickstart-guide/rpm.md @@ -0,0 +1,36 @@ +--- +sidebar_position: 3 +--- + +# RPM package + +To install the `.rpm` packages for FerretDB on your RHEL, CentOS, and other `.rpm`-based systems, +you can use `rpm` tool. + +Download the latest FerretDB `.rpm` package from [our release pages](https://github.com/FerretDB/FerretDB/releases/latest), +rename it to `ferretdb.rpm`, +then run the following command in your terminal: + +```sh +sudo rpm -i ferretdb.rpm +``` + +You can check that FerretDB was installed by running + +```sh +ferretdb --version +``` + +FerretDB does not automatically install PostgreSQL or other backends. +To install PostgreSQL, run the following commands: + +```sh +sudo yum install -y postgresql +``` + +Currently, our `.rpm` package does not provide a SystemD unit for starting FerretDB automatically. +You have to do it manually by running `ferretdb` binary with the [correct flags](../configuration/flags.md). + +Find out more about: + +- [getting logs](../configuration/observability.md#binary-executable-logs). diff --git a/website/versioned_docs/version-v1.15/quickstart-guide/windows.md b/website/versioned_docs/version-v1.15/quickstart-guide/windows.md new file mode 100644 index 000000000000..7f6b7cb8ac49 --- /dev/null +++ b/website/versioned_docs/version-v1.15/quickstart-guide/windows.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 5 +--- + +# Windows + +_This section is not currently available. +You can help FerretDB by contributing to this section. +Click the **Edit this page** link below to get started_. diff --git a/website/versioned_docs/version-v1.15/reference/_category_.yml b/website/versioned_docs/version-v1.15/reference/_category_.yml new file mode 100644 index 000000000000..72f94748ed01 --- /dev/null +++ b/website/versioned_docs/version-v1.15/reference/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Reference +position: 14 +link: + type: generated-index + slug: /reference/ + description: > + Reference pages on diagnostic commands, operators, glossary, etc. diff --git a/website/versioned_docs/version-v1.15/reference/glossary.md b/website/versioned_docs/version-v1.15/reference/glossary.md new file mode 100644 index 000000000000..36acaf43266e --- /dev/null +++ b/website/versioned_docs/version-v1.15/reference/glossary.md @@ -0,0 +1,156 @@ +--- +sidebar_position: 2 +--- + +# Glossary + +## List of FerretDB terminologies + +_This section contains a list of common terminologies related to FerretDB_. + +### A + +#### aggregation + +A way of processing documents in a collection and passing them through various operations or stages. +See [list of supported aggregation operations and commands here](supported-commands.md#aggregation-pipelines). + +#### aggregation pipeline + +A set of operators that lets you perform complex operations that aggregate and summarize values. +See [list of supported aggregation pipeline operators](supported-commands.md#aggregation-pipeline-operators) here. + +--- + +### B + +#### Beacon + +The telemetry service of FerretDB. +See [telemetry](../telemetry.md) for more details. + +#### BSON + +BSON is a serialized binary file format for storing JSON-like documents. + +#### BSON types + +The list of types that the BSON format supports. +BSON offers support for additional data types compared to JSON, such as `timestamp`, `date`, `ObjectId`, and `binary`. + +--- + +### C + +#### collection + +A group of documents in a non-relational database. +It is comparable to a table in a relational database. + +#### CRUD + +The four basic operations of a database: Create, Read, Update, and Delete. +See [Basic FerretDB CRUD operations here](../basic-operations/index.md). + +--- + +### D + +#### database + +An organized repository for collections containing its own sets of documents, and data. + +#### database command + +The set of commands in FerretDB. +For more information, see [supported commands](supported-commands.md) for more details. + +#### document + +A record in a collection that comprises key-value pairs. +See [Documents](../understanding-ferretdb.md#documents) for more. + +#### dot notation + +Dot notation is used to reference or access the elements in an array or in an embedded document. +See [dot notation](../understanding-ferretdb.md#dot-notation) for more details. + +--- + +### F + +#### field + +Similar to columns in a relational database. +They are represented as field name-value pairs and describe the kind of data in a document. + +--- + +### I + +#### index + +A data structure used for identifying and querying records in a collection. +It helps to limit the number of documents to search through or inspect in a collection. +Examples include `_id` index, user-defined index, hashed index, and partial index. +See [Indexes](../indexes.md) for more. + +--- + +### J + +#### JSON + +An acronym for JavaScript Object Notation. +It is a structured data format with human-readable text to store data objects composed of attribute-value pairs. + +#### JSONB + +JSONB is a data type of PostgreSQL that stores JSON data as a decomposed binary format. + +#### ObjectId + +A defining 12-byte type that ensures singularity and uniques within a collection and are used to represent the default values for the `_id` fields. + +#### operator + +A keyword that starts with a `$` character to query, update, or transform data. + +--- + +### O + +#### Operation modes + +FerretDB utilizes operation modes to define its approach in handling incoming requests, serving purposes such as testing, debugging, and bug reporting. +By default, FerretDB operates in `normal` mode. +See [Operation modes](../configuration/operation-modes.md) for more details. + +--- + +### P + +#### primary key + +An immutable identifier for a record. +The primary key of a documents is stored in the `_id` field, which typically contains the `ObjectId`. + +#### proxy + +Proxy is any MongoDB-compatible database that is running in parallel with FerretDB. +It's used to test differences between FerretDB and other databases. +See [Operation modes](../configuration/operation-modes.md) for more details. + +#### PostgreSQL + +An open source relational database. +FerretDB uses PostgreSQL as a database engine. + +### S + +#### SQLite + +SQLite is a self-contained, serverless system ideal for lightweight applications. +FerretDB now offers SQLite backend support. + +--- diff --git a/website/versioned_docs/version-v1.15/reference/supported-commands.md b/website/versioned_docs/version-v1.15/reference/supported-commands.md new file mode 100644 index 000000000000..8e47062c8477 --- /dev/null +++ b/website/versioned_docs/version-v1.15/reference/supported-commands.md @@ -0,0 +1,727 @@ +--- +sidebar_position: 1 +description: This is a list of all supported commands in FerretDB +--- + +# Supported commands + + + +## Query commands + +| Command | Argument | Status | Comments | +| --------------- | -------------------------- | ------ | --------------------------------------------------------- | +| `delete` | | ✅ | Basic command is fully supported | +| | `deletes` | ✅ | | +| | `comment` | ⚠️ | | +| | `let` | ⚠️ | Unimplemented | +| | `ordered` | ✅ | | +| | `writeConcern` | ⚠️ | Ignored | +| | `q` | ✅ | | +| | `limit` | ✅ | | +| | `collation` | ❌ | Unimplemented | +| | `hint` | ⚠️ | Ignored | +| `find` | | ✅ | Basic command is fully supported | +| | `filter` | ✅ | | +| | `sort` | ✅ | | +| | `projection` | ✅ | Basic projections with fields are supported | +| | `hint` | ⚠️ | Ignored | +| | `skip` | ⚠️ | | +| | `limit` | ✅ | | +| | `batchSize` | ✅ | | +| | `singleBatch` | ✅ | | +| | `comment` | ⚠️ | | +| | `maxTimeMS` | ✅ | | +| | `readConcern` | ⚠️ | Ignored | +| | `max` | ⚠️ | Ignored | +| | `min` | ⚠️ | Ignored | +| | `returnKey` | ❌ | Unimplemented | +| | `showRecordId` | ✅ | | +| | `tailable` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2283) | +| | `oplogReplay` | ❌ | Unimplemented | +| | `noCursorTimeout` | ❌ | Unimplemented | +| | `awaitData` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2283) | +| | `allowPartialResults` | ❌ | Unimplemented | +| | `collation` | ❌ | Unimplemented | +| | `allowDiskUse` | ⚠️ | Ignored | +| | `let` | ❌ | Unimplemented | +| `findAndModify` | | ✅ | Basic command is fully supported | +| | `query` | ✅ | | +| | `sort` | ✅ | | +| | `remove` | ✅ | | +| | `update` | ✅ | | +| | `new` | ✅ | | +| | `upsert` | ✅ | | +| | `bypassDocumentValidation` | ⚠️ | Ignored | +| | `writeConcern` | ⚠️ | Ignored | +| | `maxTimeMS` | ✅ | | +| | `collation` | ❌ | Unimplemented | +| | `arrayFilters` | ❌ | Unimplemented | +| | `hint` | ⚠️ | Ignored | +| | `comment` | ⚠️ | | +| | `let` | ⚠️ | Unimplemented | +| `getMore` | | ✅ | Basic command is fully supported | +| | `batchSize` | ✅ | | +| | `maxTimeMS` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2984) | +| | `comment` | ⚠️ | Unimplemented | +| `insert` | | ✅ | Basic command is fully supported | +| | `documents` | ✅ | | +| | `ordered` | ✅ | | +| | `bypassDocumentValidation` | ⚠️ | Ignored | +| | `comment` | ⚠️ | Ignored | +| `update` | | ✅ | Basic command is fully supported | +| | `updates` | ✅ | | +| | `ordered` | ⚠️ | Ignored | +| | `writeConcern` | ⚠️ | Ignored | +| | `bypassDocumentValidation` | ⚠️ | Ignored | +| | `comment` | ⚠️ | | +| | `let` | ⚠️ | Unimplemented | +| | `q` | ✅ | | +| | `u` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2742) | +| | `c` | ⚠️ | Unimplemented | +| | `upsert` | ✅ | | +| | `multi` | ✅ | | +| | `collation` | ❌ | Unimplemented | +| | `arrayFilters` | ⚠️ | Unimplemented | +| | `hint` | ⚠️ | Ignored | + +### Update Operators + +The following operators and modifiers are available in the `update` and `findAndModify` commands. + +| Operator | Modifier | Status | Comments | +| ----------------- | ----------- | ------ | -------------------------------------------------------- | +| `$currentDate` | | ✅ | | +| `$inc` | | ✅ | | +| `$min` | | ✅ | | +| `$max` | | ✅ | | +| `$mul` | | ✅ | | +| `$rename` | | ✅ | | +| `$set` | | ✅ | | +| `$setOnInsert` | | ✅ | | +| `$unset` | | ✅ | | +| `$` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/822) | +| `$[]` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/823) | +| `$[]` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/824) | +| `$addToSet` | | ✅️ | | +| `$pop` | | ✅ | | +| `$pull` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/826) | +| `$push` | | ✅️ | | +| `$pullAll` | | ✅️ | | +| | `$each` | ✅️ | | +| | `$position` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/829) | +| | `$slice` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/830) | +| | `$sort` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/831) | +| | `$bit` | ✅️ | | + +### Projection Operators + +The following operators are available in the `find` command `projection` argument. + +| Operator | Status | Comments | +| ------------ | ------ | --------------------------------------------------------- | +| `$` | ✅️ | | +| `$elemMatch` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1710) | +| `$meta` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1712) | +| `$slice` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1711) | + +## Query Plan Cache Commands + +Related [issue](https://github.com/FerretDB/FerretDB/issues/78). + +| Command | Argument | Status | Comments | +| ----------------------- | ------------ | ------ | --------------------------------------------------------- | +| `planCacheClear` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1502) | +| | `query` | ⚠️ | | +| | `projection` | ⚠️ | | +| | `sort` | ⚠️ | | +| | `comment` | ⚠️ | | +| `planCacheClearFilters` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1503) | +| | `query` | ⚠️ | | +| | `sort` | ⚠️ | | +| | `projection` | ⚠️ | | +| | `collation` | ❌ | Unimplemented | +| | `comment` | ⚠️ | | +| `planCacheListFilters` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1504) | +| | `comment` | ⚠️ | | +| `planCacheSetFilter` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1505) | +| | `query` | ⚠️ | | +| | `sort` | ⚠️ | | +| | `projection` | ⚠️ | | +| | `collation` | ❌ | Unimplemented | +| | `indexes` | ⚠️ | | +| | `comment` | ⚠️ | | + +## Free Monitoring Commands + +| Command | Argument | Status | Comments | +| ------------------------- | ------------------- | ------ | ---------------------------------------------------------- | +| `setFreeMonitoring` | | ✅ | [Telemetry reporting](../telemetry.md) | +| | `action: "enable"` | ✅ | [`--telemetry=enable`](../telemetry.md#enable-telemetry) | +| | `action: "disable"` | ✅ | [`--telemetry=disable`](../telemetry.md#disable-telemetry) | +| `getFreeMonitoringStatus` | | ✅ | | + +## Database Operations + +### User Management Commands + +| Command | Argument | Status | Comments | +| -------------------------- | -------------------------------- | ------ | --------------------------------------------------------- | +| `createUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1491) | +| | `pwd` | ⚠️ | | +| | `customData` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `mechanisms` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropAllUsersFromDatabase` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1492) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1493) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `grantRolesToUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1494) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `revokeRolesFromUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1495) | +| | `roles` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `updateUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1496) | +| | `pwd` | ⚠️ | | +| | `customData` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `mechanisms` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `comment` | ⚠️ | | +| `usersInfo` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1497) | +| | `showCredentials` | ⚠️ | | +| | `showCustomData` | ⚠️ | | +| | `showPrivileges` | ⚠️ | | +| | `showAuthenticationRestrictions` | ⚠️ | | +| | `filter` | ⚠️ | | +| | `comment` | ⚠️ | | + +### Authentication Commands + +| Command | Argument | Status | Comments | +| -------------- | -------- | ------ | --------------------------------------------------------- | +| `authenticate` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1731) | +| `getnonce` | | ❌ | Deprecated | +| `logout` | | ✅ | | +| `saslStart` | | ✅ | | + +### Role Management Commands + +| Command | Argument | Status | Comments | +| -------------------------- | ---------------------------- | ------ | --------------------------------------------------------- | +| `createRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1528) | +| | `privileges` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1529) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropAllRolesFromDatabase` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1530) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `grantPrivilegesToRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1531) | +| | `privileges` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `grantRolesToRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1532) | +| | `roles` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `invalidateUserCache` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1533) | +| `revokePrivilegesFromRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1534) | +| | `privileges` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `revokeRolesFromRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1535) | +| | `roles` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `rolesInfo` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1536) | +| | `showPrivileges` | ⚠️ | | +| | `showBuiltinRoles` | ⚠️ | | +| | `comment` | ⚠️ | | +| `updateRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1537) | +| | `privileges` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | + +## Session Commands + +Related [issue](https://github.com/FerretDB/FerretDB/issues/8). + +Related [issue](https://github.com/FerretDB/FerretDB/issues/153). + +| Command | Argument | Status | Comments | +| -------------------------- | -------------- | ------ | --------------------------------------------------------- | +| `abortTransaction` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1547) | +| | `txnNumber` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `autocommit` | ⚠️ | | +| | `comment` | ⚠️ | | +| `commitTransaction` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1548) | +| | `txnNumber` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `autocommit` | ⚠️ | | +| | `comment` | ⚠️ | | +| `endSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1549) | +| `killAllSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1550) | +| `killAllSessionsByPattern` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1551) | +| `killSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1552) | +| `refreshSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1553) | +| `startSession` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1554) | + +## Aggregation pipelines + +Related [issue](https://github.com/FerretDB/FerretDB/issues/1917). + +| Command | Argument | Status | Comments | +| ----------- | -------- | ------ | -------- | +| `aggregate` | | ✅️ | | +| `count` | | ✅ | | +| `distinct` | | ✅ | | + +### Aggregation pipeline stages + +| Stage | Status | Comments | +| -------------------- | ------ | --------------------------------------------------------- | +| `$addFields` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/1413) | +| `$bucket` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1414) | +| `$bucketAuto` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1414) | +| `$changeStream` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1415) | +| `$changeStream` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1415) | +| `$collStats` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2447) | +| `$count` | ✅️ | | +| `$currentOp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1444) | +| `$densify` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1418) | +| `$documents` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1419) | +| `$documents` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1419) | +| `$facet` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1420) | +| `$fill` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1421) | +| `$geoNear` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1412) | +| `$graphLookup` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1422) | +| `$group` | ✅️ | | +| `$indexStats` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1424) | +| `$limit` | ✅️ | | +| `$listLocalSessions` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1426) | +| `$listSessions` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1426) | +| `$lookup` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1427) | +| `$match` | ✅ | | +| `$merge` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1429) | +| `$out` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1430) | +| `$planCacheStats` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1431) | +| `$project` | ✅ | | +| `$redact` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1433) | +| `$replaceRoot` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1434) | +| `$replaceWith` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1434) | +| `$sample` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1435) | +| `$search` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1436) | +| `$searchMeta` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1436) | +| `$set` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/1413) | +| `$setWindowFields` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1437) | +| `$skip` | ✅️ | | +| `$sort` | ✅️ | | +| `$sortByCount` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1440) | +| `$unionWith` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1441) | +| `$unset` | ✅️ | | +| `$unwind` | ✅️ | | + +### Aggregation pipeline operators + +| Operator | Status | Comments | +| ------------------------- | ------ | --------------------------------------------------------- | +| `$abs` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$accumulator` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$acos` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$acosh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$add` (arithmetic) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$add` (date) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$addToSet` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$allElementsTrue` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$and` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1455) | +| `$anyElementTrue` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$arrayElemAt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$arrayToObject` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$asin` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$asinh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$atan` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$atan2` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$atanh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$avg` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$binarySize` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1459) | +| `$bottom` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$bottomN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$bsonSize` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1459) | +| `$ceil` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$cmp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$concat` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$concatArrays` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$cond` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1457) | +| `$convert` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$cos` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$cosh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$count` | ✅️ | | +| `$covariancePop` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$covarianceSamp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$dateAdd` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateDiff` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateFromParts` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateFromString` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateSubtract` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateToParts` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateToString` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateTrunc` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dayOfMonth` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dayOfWeek` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dayOfYear` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$degreesToRadians` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$denseRank` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$derivative` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$divide` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$documentNumber` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$eq` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$exp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$expMovingAvg` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$filter` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$first` (accumulator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$first` (array operator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$firstN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$floor` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$function` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1458) | +| `$getField` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1471) | +| `$gt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$gte` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$hour` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$ifNull` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1457) | +| `$in` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$indexOfArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$indexOfBytes` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$indexOfCP` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$integral` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$isArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$isNumber` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$isoDayOfWeek` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$isoWeek` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$isoWeekYear` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$last` (accumulator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$last` (array operator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$lastN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$let` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1469) | +| `$linearFill` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$literal` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1470) | +| `$ln` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$locf` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$log` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$log10` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$lt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$lte` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$ltrim` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$map` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$max` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$maxN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$mergeObjects` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$meta` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$millisecond` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$min` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$minN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$minute` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$mod` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$month` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$multiply` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$ne` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$not` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1455) | +| `$objectToArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1461) | +| `$or` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1455) | +| `$pow` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$push` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$radiansToDegrees` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$rand` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/541) | +| `$range` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$rank` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$reduce` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$regexFind` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$regexFindAll` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$regexMatch` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$replaceAll` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$replaceOne` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$reverseArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$round` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$rtrim` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$sampleRate` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1472) | +| `$second` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$setDifference` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setEquals` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setField` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1461) | +| `$setIntersection` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setIsSubset` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setUnion` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$shift` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$sin` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$sinh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$size` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$slice` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$sortArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$split` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$sqrt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$stdDevPop` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$stdDevSamp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$strcasecmp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$strLenBytes` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$strLenCP` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$substr` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$substrBytes` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$substrCP` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$subtract` (arithmetic) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$subtract` (date) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$sum` (accumulator) | ✅️ | | +| `$sum` (operator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2680) | +| `$switch` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1457) | +| `$tan` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$tanh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$toBool` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toDate` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$toDecimal` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toDouble` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toInt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toLong` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toLower` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$toObjectId` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$top` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$topN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$toString` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toUpper` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$trim` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$trunc` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$tsIncrement` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1464) | +| `$tsSecond` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1464) | +| `$type` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$unsetField` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1461) | +| `$week` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$year` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$zip` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | + +## Administration commands + +| Command | Argument / Option | Property | Status | Comments | +| --------------------------------- | ------------------------------ | ------------------------- | ------ | --------------------------------------------------------- | +| `cloneCollectionAsCapped` | | | ❌ | | +| | `toCollection` | | ⚠️ | | +| | `size` | | ⚠️ | | +| | `writeConcern` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `collMod` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1510) | +| | `index` | | ⚠️ | | +| | | `keyPattern` | ⚠️ | | +| | | `name` | ⚠️ | | +| | | `expireAfterSeconds` | ⚠️ | | +| | | `hidden` | ⚠️ | | +| | | `prepareUnique` | ⚠️ | | +| | | `unique` | ⚠️ | | +| | `validator` | | ⚠️ | | +| | | `validationLevel` | ⚠️ | | +| | | `validationAction` | ⚠️ | | +| | `viewOn` (Views) | | ⚠️ | | +| | `pipeline` (Views) | | ⚠️ | | +| | `cappedSize` | | ⚠️ | | +| | `cappedMax` | | ⚠️ | | +| | `changeStreamPreAndPostImages` | | ⚠️ | | +| `compact` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/3466) | +| | `force` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `compactStructuredEncryptionData` | | | ❌ | | +| | `compactionTokens` | | ⚠️ | | +| `convertToCapped` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/3457) | +| | `size` | | ⚠️ | | +| | `writeConcern` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `create` | | | ✅ | | +| | `capped` | | ✅️ | | +| | `timeseries` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/177) | +| | | `timeField` | ⚠️ | | +| | | `metaField` | ⚠️ | | +| | | `granularity` | ⚠️ | | +| | `expireAfterSeconds` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2415) | +| | `clusteredIndex` | | ⚠️ | | +| | `changeStreamPreAndPostImages` | | ⚠️ | | +| | `autoIndexId` | | ⚠️ | Ignored | +| | `size` | | ✅️ | | +| | `max` | | ✅ | | +| | `storageEngine` | | ⚠️ | Ignored | +| | `validator` | | ⚠️ | Not implemented in PostgreSQL | +| | `validationLevel` | | ⚠️ | Unimplemented | +| | `validationAction` | | ⚠️ | Unimplemented | +| | `indexOptionDefaults` | | ⚠️ | Ignored | +| | `viewOn` | | ⚠️ | Unimplemented | +| | `pipeline` | | ⚠️ | Unimplemented | +| | `collation` | | ❌ | Unimplemented | +| | `writeConcern` | | ⚠️ | Ignored | +| | `encryptedFields` | | ⚠️ | | +| | `comment` | | ⚠️ | Ignored | +| `createIndexes` | | | ✅ | | +| | `indexes` | | ✅ | | +| | | `key` | ✅ | | +| | | `name` | ✅️ | | +| | | `unique` | ✅ | | +| | | `partialFilterExpression` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2448) | +| | | `sparse` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2448) | +| | | `expireAfterSeconds` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2415) | +| | | `hidden` | ❌ | Unimplemented | +| | | `storageEngine` | ❌ | Unimplemented | +| | | `weights` | ❌ | Unimplemented | +| | | `default_language` | ❌ | Unimplemented | +| | | `language_override` | ❌ | Unimplemented | +| | | `textIndexVersion` | ❌ | Unimplemented | +| | | `2dsphereIndexVersion` | ❌ | Unimplemented | +| | | `bits` | ❌ | Unimplemented | +| | | `min` | ❌ | Unimplemented | +| | | `max` | ❌ | Unimplemented | +| | | `bucketSize` | ❌ | Unimplemented | +| | | `collation` | ❌ | Unimplemented | +| | | `wildcardProjection` | ❌ | Unimplemented | +| | `writeConcern` | | ⚠️ | | +| | `commitQuorum` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `currentOp` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2399) | +| | `$ownOps` | | ⚠️ | | +| | `$all` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `drop` | | | ✅ | | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `dropDatabase` | | | ✅ | | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `dropConnections` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1511) | +| | `hostAndPort` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `dropIndexes` | | | ✅ | | +| | `index` | | ✅ | | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `filemd5` | | | ❌ | | +| `fsync` | | | ❌ | | +| `fsyncUnlock` | | | ❌ | | +| | `lock` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `getDefaultRWConcern` | | | ❌ | | +| | `inMemory` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `getClusterParameter` | | | ❌ | | +| `getParameter` | | | ❌ | | +| | `comment` | | ⚠️ | | +| `killCursors` | | | ✅ | | +| | `cursors` | | ✅ | | +| | `comment` | | ⚠️ | | +| `killOp` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1515) | +| | `op` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `listCollections` | | | ✅ | | +| | `filter` | | ✅ | | +| | `nameOnly` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/3624) | +| | `authorizedCollections` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/3770) | +| | `comment` | | ⚠️ | | +| `listDatabases` | | | ✅ | | +| | `filter` | | ✅ | | +| | `nameOnly` | | ✅ | | +| | `authorizedDatabases` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/3769) | +| | `comment` | | ⚠️ | Ignored | +| `listIndexes` | | | ✅ | | +| | `cursor.batchSize` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `logRotate` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1959) | +| | `` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `reIndex` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1516) | +| `renameCollection` | | | ✅ | | +| | `to` | | ✅ | [Issue](https://github.com/FerretDB/FerretDB/issues/2563) | +| | `dropTarget` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2565) | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `rotateCertificates` | | | ❌ | | +| `setFeatureCompatibilityVersion` | | | ❌ | | +| `setIndexCommitQuorum` | | | ❌ | | +| | `setIndexCommitQuorum` | | ⚠️ | | +| | `indexNames` | | ⚠️ | | +| | `commitQuorum` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `setParameter` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1518) | +| `setDefaultRWConcern` | | | ❌ | | +| | `defaultReadConcern` | | ⚠️ | | +| | `defaultWriteConcern` | | ⚠️ | | +| | `writeConcern` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `shutdown` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1519) | +| | `force` | | ⚠️ | | +| | `timeoutSecs` | | ⚠️ | | +| | `comment` | | ⚠️ | | + +## Diagnostic commands + +| Command | Argument | Status | Comments | +| -------------------- | ---------------------- | ------ | -------------------------------- | +| `buildInfo` | | ✅ | Basic command is fully supported | +| `collStats` | | ✅ | Basic command is fully supported | +| | `collStats` | ✅ | | +| | `scale` | ✅ | | +| `connPoolStats` | | ❌ | Unimplemented | +| `connectionStatus` | | ✅ | Basic command is fully supported | +| | `showPrivileges` | ✅ | | +| `dataSize` | | ✅ | Basic command is fully supported | +| | `keyPattern` | ⚠️ | Unimplemented | +| | `min` | ⚠️ | Unimplemented | +| | `max` | ⚠️ | Unimplemented | +| | `estimate` | ⚠️ | Ignored | +| `dbHash` | | ❌ | Unimplemented | +| | `collection` | ⚠️ | | +| `dbStats` | | ✅ | Basic command is fully supported | +| | `scale` | ✅ | | +| | `freeStorage` | ⚠️ | Unimplemented | +| `driverOIDTest` | | ⚠️ | Unimplemented | +| `explain` | | ✅ | Basic command is fully supported | +| | `verbosity` | ⚠️ | Ignored | +| | `comment` | ⚠️ | Unimplemented | +| `features` | | ❌ | Unimplemented | +| `getCmdLineOpts` | | ✅ | Basic command is fully supported | +| `getLog` | | ✅ | Basic command is fully supported | +| `hostInfo` | | ✅ | Basic command is fully supported | +| `_isSelf` | | ❌ | Unimplemented | +| `listCommands` | | ✅ | Basic command is fully supported | +| `lockInfo` | | ❌ | Unimplemented | +| `netstat` | | ❌ | Unimplemented | +| `ping` | | ✅ | Basic command is fully supported | +| `profile` | | ❌ | Unimplemented | +| | `slowms` | ⚠️ | | +| | `sampleRate` | ⚠️ | | +| | `filter` | ⚠️ | | +| `serverStatus` | | ✅ | Basic command is fully supported | +| `shardConnPoolStats` | | ❌ | Unimplemented | +| `top` | | ❌ | Unimplemented | +| `validate` | | ✅ | Basic command is fully supported | +| | `full` | ⚠️ | | +| | `repair` | ⚠️ | | +| | `metadata` | ⚠️ | | +| | `checkBSONConformance` | ⚠️ | | +| `validateDBMetadata` | | ❌ | Unimplemented | +| | `apiParameters` | ⚠️ | | +| | `db` | ⚠️ | | +| | `collections` | ⚠️ | | +| `whatsmyuri` | | ✅ | Basic command is fully supported | diff --git a/website/versioned_docs/version-v1.15/security/_category_.yml b/website/versioned_docs/version-v1.15/security/_category_.yml new file mode 100644 index 000000000000..aa19bc8c4576 --- /dev/null +++ b/website/versioned_docs/version-v1.15/security/_category_.yml @@ -0,0 +1,7 @@ +--- +label: Security +position: 13 +link: + type: generated-index + slug: /security/ + description: Authentication and TLS diff --git a/website/versioned_docs/version-v1.15/security/authentication.md b/website/versioned_docs/version-v1.15/security/authentication.md new file mode 100644 index 000000000000..ddbfe79ab29c --- /dev/null +++ b/website/versioned_docs/version-v1.15/security/authentication.md @@ -0,0 +1,105 @@ +--- +sidebar_position: 1 +slug: /security/authentication/ # referenced in error messages +description: Learn to use authentication mechanisms +--- + +# Authentication + +FerretDB does not store authentication information (usernames and passwords) itself but uses the backend's authentication mechanisms. +The default username and password can be specified in FerretDB's connection string, +but the client could use a different user by providing a username and password in MongoDB URI. +For example, if the server was started with `postgres://user1:pass1@postgres:5432/ferretdb`, +anonymous clients will be authenticated as user1, +but clients that use `mongodb://user2:pass2@ferretdb:27018/ferretdb?tls=true&authMechanism=PLAIN` MongoDB URI will be authenticated as user2. +Since usernames and passwords are transferred in plain text, +the use of [TLS](../security/tls-connections.md) is highly recommended. + +## PostgreSQL backend with default username and password + +In following examples, default username and password are specified in FerretDB's connection string `user1:pass1`. +Ensure `user1` is a PostgreSQL user with necessary +[privileges](https://www.postgresql.org/docs/current/sql-grant.html). +See more about [creating PostgreSQL user](https://www.postgresql.org/docs/current/sql-createuser.html) +and [PostgreSQL authentication methods](https://www.postgresql.org/docs/current/auth-methods.html). + +### Using `ferretdb` package + +Start `ferretdb` by specifying `--postgresql-url` with default username and password. + +```sh +ferretdb --postgresql-url=postgres://user1:pass1@localhost:5432/ferretdb +``` + +An anonymous client is authenticated with default `user1` from `--postgresql-url`. + +```sh +mongosh 'mongodb://127.0.0.1/ferretdb' +``` + +A client that specify username and password in MongoDB URI as below is authenticated as `user2`. + +```sh +mongosh 'mongodb://user2:pass2@127.0.0.1/ferretdb?authMechanism=PLAIN' +``` + +### Using Docker + +For Docker, specify `FERRETDB_POSTGRESQL_URL` with default username and password. + +```yaml +services: + postgres: + image: postgres + environment: + - POSTGRES_USER=username + - POSTGRES_PASSWORD=password + - POSTGRES_DB=ferretdb + volumes: + - ./data:/var/lib/postgresql/data + + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27017:27017 + environment: + - FERRETDB_POSTGRESQL_URL=postgres://user1:pass1@postgres:5432/ferretdb + +networks: + default: + name: ferretdb +``` + +To start `ferretdb`, use docker compose. + +```sh +docker compose up +``` + +An anonymous client is authenticated with `user1` from `FERRETDB_POSTGRESQL_URL`. +Use following command to run `mongosh` inside the temporary MongoDB container, +attached to the same Docker network. + +```sh +docker run --rm -it --network=ferretdb --entrypoint=mongosh \ + mongo 'mongodb://ferretdb/ferretdb' +``` + +A client that specify username and password in MongoDB URI as below is authenticated as `user2`. + +```sh +docker run --rm -it --network=ferretdb --entrypoint=mongosh \ + mongo 'mongodb://user2:pass2@ferretdb/ferretdb?authMechanism=PLAIN' +``` + +## Authentication Handshake + +:::note +Some drivers may still use the legacy `hello` command to complete a handshake. +::: + +If you encounter any issues while authenticating with FerretDB, try setting the Stable API version to V1 on the client as this may prevent legacy commands from being used. +Please refer to your specific driver documentation on how to set this field. + +If this does not resolve your issue please file a bug report [here](https://github.com/FerretDB/FerretDB/issues/new?assignees=ferretdb-bot&labels=code%2Fbug%2Cnot+ready&projects=&template=bug.yml). diff --git a/website/versioned_docs/version-v1.15/security/tls-connections.md b/website/versioned_docs/version-v1.15/security/tls-connections.md new file mode 100644 index 000000000000..68901490a694 --- /dev/null +++ b/website/versioned_docs/version-v1.15/security/tls-connections.md @@ -0,0 +1,121 @@ +--- +sidebar_position: 2 +description: Learn to secure connections using TLS +--- + +# TLS Connections + +It is possible to encrypt connections between FerretDB and clients by using TLS. +All you need to do is to start the server with the following flags or environment variables: + +- `--listen-tls` / `FERRETDB_LISTEN_TLS` specifies the TCP hostname and port + that will be used for listening for incoming TLS connections. + If empty, TLS listener is disabled; +- `--listen-tls-cert-file` / `FERRETDB_LISTEN_TLS_CERT_FILE` specifies the PEM encoded, TLS certificate file + that will be presented to clients; +- `--listen-tls-key-file` / `FERRETDB_LISTEN_TLS_KEY_FILE` specifies the TLS private key file + that will be used to decrypt communications; +- `--listen-tls-ca-file` / `FERRETDB_LISTEN_TLS_CA_FILE` specifies the root CA certificate file + that will be used to verify client certificates. + +Then use `tls` query parameters in MongoDB URI for the client. +You may also need to set `tlsCAFile` parameter if the system-wide certificate authority did not issue the server's certificate. +See documentation for your client or driver for more details. +Example: `mongodb://ferretdb:27018/?tls=true&tlsCAFile=companyRootCA.pem`. + +## PostgreSQL backend with TLS + +Using TLS is recommended if username and password are transferred in plain text. + +In following examples, FerretDB uses TLS certificates to secure the connection. +Example certificates are found in [build/certs](https://github.com/FerretDB/FerretDB/tree/main/build/certs). +The `ferretdb` server uses TLS server certificate file, TLS private key file and root CA certificate file. + +```text +server-certs/ +├── rootCA-cert.pem +├── server-cert.pem +└── server-key.pem +``` + +The client uses TLS client certificate file and root CA certificate file. + +```text +client-certs/ +├── client.pem +└── rootCA-cert.pem +``` + +### Using TLS with `ferretdb` package + +The example below connects to localhost PostgreSQL instance using TLS with certificates in `server-certs` directory. +Be sure to check that `server-certs` directory and files are present. + +```sh +ferretdb \ + --postgresql-url=postgres://localhost:5432/ferretdb \ + --listen-tls=:27018 \ + --listen-tls-cert-file=./server-certs/server-cert.pem \ + --listen-tls-key-file=./server-certs/server-key.pem \ + --listen-tls-ca-file=./server-certs/rootCA-cert.pem +``` + +Using `mongosh`, a client connects to ferretdb as `user2` using TLS certificates in `client-certs` directory. +Be sure to check that `client-certs` directory and files are present. + +```sh +mongosh 'mongodb://user2:pass2@127.0.0.1:27018/ferretdb?authMechanism=PLAIN&tls=true&tlsCertificateKeyFile=./client-certs/client.pem&tlsCaFile=./client-certs/rootCA-cert.pem' +``` + +### Using TLS with Docker + +For using Docker to run `ferretdb` server, `docker-compose.yml` example for TLS is provided in below. +The Docker host requires certificates `server-certs` directory, +and volume is mounted from `./server-certs` of Docker host to `/etc/certs` of Docker container. + +```yaml +services: + postgres: + image: postgres + environment: + - POSTGRES_USER=username + - POSTGRES_PASSWORD=password + - POSTGRES_DB=ferretdb + volumes: + - ./data:/var/lib/postgresql/data + + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27018:27018 + environment: + - FERRETDB_POSTGRESQL_URL=postgres://postgres:5432/ferretdb + - FERRETDB_LISTEN_TLS=:27018 + - FERRETDB_LISTEN_TLS_CERT_FILE=/etc/certs/server-cert.pem + - FERRETDB_LISTEN_TLS_KEY_FILE=/etc/certs/server-key.pem + - FERRETDB_LISTEN_TLS_CA_FILE=/etc/certs/rootCA-cert.pem + volumes: + - ./server-certs:/etc/certs + +networks: + default: + name: ferretdb +``` + +To start `ferretdb`, use docker compose. + +```sh +docker compose up +``` + +In the following example, a client connects to MongoDB URI using TLS certificates as `user2`. +It uses Docker volume to mount `./clients-certs` of Docker host to `/clients` Docker container. + +```sh +docker run --rm -it \ + --network=ferretdb \ + --volume ./client-certs:/clients \ + --entrypoint=mongosh \ + mongo 'mongodb://user2:pass2@host.docker.internal:27018/ferretdb?authMechanism=PLAIN&tls=true&tlsCertificateKeyFile=/clients/client.pem&tlsCaFile=/clients/rootCA-cert.pem' +``` diff --git a/website/versioned_docs/version-v1.15/telemetry.md b/website/versioned_docs/version-v1.15/telemetry.md new file mode 100644 index 000000000000..281fcb991ee7 --- /dev/null +++ b/website/versioned_docs/version-v1.15/telemetry.md @@ -0,0 +1,153 @@ +--- +sidebar_position: 12 +slug: /telemetry/ # referenced in many places; must not change +--- + +# Telemetry reporting + +FerretDB collects basic anonymous usage data and sends them to our telemetry service ([FerretDB Beacon](https://beacon.ferretdb.io)), +which helps us understand its usage, and how we can further increase compatibility and enhance our product. +It also enables us to provide you information about available updates. + +Your privacy is important to us, and we understand how sensitive data collection can be, +which is why we are not collecting any personally-identifying information +or share any of the data with third parties. + +The following data is collected: + +- FerretDB version +- Random instance UUID +- [Autonomous system]() number, + cloud provider region, or country derived from IP address (but the IP address itself) +- Uptime +- Backend (PostgreSQL or SQLite) version +- Installation type (Docker, package, cloud provider marketplace, self-built) +- Build configuration (Go version, build flags and tags) +- Command statistics: + - protocol operation codes (e.g. `OP_MSG`, `OP_QUERY`); + - command names (e.g. `find`, `aggregate`); + - arguments (e.g. `sort`, `$count (stage)`); + - error codes (e.g. `NotImplemented`, `InternalError`; or `ok`). + +:::info +Argument values, data field names, successful responses, or error messages are never collected. +::: + +## Version notification + +When a FerretDB update is available, +the telemetry service sends periodic notifications containing information about the latest FerretDB version. +This information is logged in the server logs and `startupWarnings` command output. + +While you may not upgrade to the latest release immediately, +ensure that you update early to take advantage of recent bug fixes, new features, and performance improvements. + +## Configure telemetry + +The telemetry reporter has three state settings: `enabled`, `disabled`, and `undecided` (default). +The latter acts as if it is `enabled` with two differences: + +- When `enabled`, the first report is sent right after FerretDB starts. + If `undecided`, the first report is delayed by one hour. + That should give you enough time to disable it if you decide to do so. +- Similarly, when `enabled`, the last report is sent right before FerretDB shuts down. + That does not happen when `undecided`. + +:::info +`undecided` state does not automatically change into `enabled` or `disabled` after the first or any other report. +Explicit user action is required (see below) to change an `undecided` state to `enabled` or `disabled`. +::: + +Telemetry reporting is always disabled for [embedded FerretDB](https://pkg.go.dev/github.com/FerretDB/FerretDB/ferretdb) +and can't be configured. + +:::info +Despite the autogenerated message by `mongosh` regarding MongoDB's free cloud-based monitoring service, please note that no data will ever be shared with MongoDB Inc. +::: + +### Disable telemetry + +We urge you not to disable telemetry reporter, as its insights will help us enhance our software. + +While we are grateful for these usage insights, we understand that not everyone is comfortable with sending them. + +:::caution +If you disable telemetry, automated version checks and information on updates will not be available. +::: + +Telemetry can be disabled using any of the following options: + +1. Pass the command-line flag `--telemetry` to the FerretDB executable with value: + `0`, `f`, `false`, `n`, `no`, `off`, `disable`, `disabled`, `optout`, `opt-out`, `disallow`, `forbid`. + + ```sh + --telemetry=disable + ``` + +2. Set the environment variable `FERRETDB_TELEMETRY`. + + ```sh + export FERRETDB_TELEMETRY=disable + ``` + +3. Set the `DO_NOT_TRACK` environment variable with any of the following values: + `1`, `t`, `true`, `y`, `yes`, `on`, `enable`, `enabled`. + + ```sh + export DO_NOT_TRACK=true + ``` + +4. Rename FerretDB executable to include a `donottrack` string. + + :::caution + If telemetry is disabled using this option, you cannot use the `--telemetry` flag or environment variables + until the `donottrack` string is removed. + ::: + +5. Use the `db.disableFreeMonitoring()` command on runtime. + + ```js + db.disableFreeMonitoring() + ``` + + :::caution + If the telemetry is set via a command-line flag, an environment variable or a filename, it's not possible + to modify its state via command. + ::: + +### Enable telemetry + +Telemetry can be explicitly enabled (see [above](#configure-telemetry)) with the command-line flag `--telemetry` +by setting one of the values: +`1`, `t`, `true`, `y`, `yes`, `on`, `enable`, `enabled`, `optin`, `opt-in`, `allow`. + +```sh +--telemetry=enable +``` + +You can also use `FERRETDB_TELEMETRY` environment variable with same values +or on runtime via `db.enableFreeMonitoring()` command. + +```sh +export FERRETDB_TELEMETRY=enable +``` + +```js +db.enableFreeMonitoring() +``` + +One case when explicitly enabling telemetry is useful is if you want to help us improve compatibility +with your application by running its integration tests or just by testing it manually. +If you leave the telemetry state undecided and your test lasts less than an hour, +we will not have data about unimplemented commands and errors. + +If you want to help us with that, please do the following: + +1. Start FerretDB with [debug logging](configuration/flags.md) and telemetry explicitly enabled. + Confirm that telemetry is enabled from the logs. +2. Test your application with integration tests or manually. +3. Gracefully stop FerretDB with `SIGTERM` or `docker stop` (not with `SIGKILL` or `docker kill`). +4. Optionally, locate instance UUID in the `state.json` file in the state directory + (`/state` for Docker, current directory otherwise) and send it to us. + That would allow us to locate your data and understand what FerretDB functionality + should be implemented or fixed to improve compatibility with your application. diff --git a/website/versioned_docs/version-v1.15/understanding-ferretdb.md b/website/versioned_docs/version-v1.15/understanding-ferretdb.md new file mode 100644 index 000000000000..c866497ea45e --- /dev/null +++ b/website/versioned_docs/version-v1.15/understanding-ferretdb.md @@ -0,0 +1,197 @@ +--- +sidebar_position: 2 +--- + +# Understanding FerretDB + +FerretDB is an open-source proxy that translates MongoDB wire protocol queries to SQL, +with PostgreSQL or SQLite as the database engine. +It uses the same commands, drivers, and tools as MongoDB. + +```mermaid +flowchart LR + A["Any application\nAny MongoDB driver"] + F{{FerretDB}} + P[(PostgreSQL)] + S[("SQLite")] + + A -- "MongoDB protocol\nBSON" --> F + F -- "PostgreSQL protocol\nSQL" --> P + F -. "SQLite library\nSQL" .-> S +``` + +:::tip +New to FerretDB? + +Check out our: + +- [Installation guide](quickstart-guide/docker.md) +- [Key differences](diff.md) +- [Basic CRUD operations](basic-operations/index.md) + +::: + +## Supported backends + +:::caution +FerretDB is under constant development. +As with any database, before moving to production, please verify if it is suitable for your application. +::: + +### PostgreSQL + +PostgreSQL backend is our main backend and is fully supported. + +PostgreSQL should be configured with `UTF8` encoding and one of the following locales: +`POSIX`, `C`, `C.UTF8`, `en_US.UTF8`. + +MongoDB databases are mapped to PostgreSQL schemas in a single PostgreSQL database that should be created in advance. +MongoDB collections are mapped to PostgreSQL tables. +MongoDB documents are mapped to rows with a single [JSONB](https://www.postgresql.org/docs/current/datatype-json.html) column. +Those mappings will change as we work on improving compatibility and performance, +but no breaking changes will be introduced without a major version bump. + +### SQLite + +We also support the [SQLite](https://www.sqlite.org/) backend. + +MongoDB databases are mapped to SQLite database files. +MongoDB collections are mapped to SQLite tables. +MongoDB documents are mapped to rows with a single [JSON1](https://www.sqlite.org/json1.html) column. +Those mappings will change as we work on improving compatibility and performance, +but no breaking changes will be introduced without a major version bump. + +### SAP HANA (alpha) + +Currently, [we are also working](https://blogs.sap.com/2022/12/13/introduction-to-sap-hana-compatibility-layer-for-mongodb-wire-protocol/) +with SAP on HANA compatibility. +It is not officially supported yet. + +## Documents + +Documents are self-describing records containing both data types and a description of the data being stored. +They are similar to rows in relational databases. +Here is an example of a single document: + +```js +{ + first: "Thomas", + last: "Edison", + invention: "Lightbulb", + birth: 1847 +} +``` + +The above data is stored in a single document. + +:::note +FerretDB follows almost the same naming conventions as MongoDB. +However, there are a few restrictions, which you can find [here](diff.md). +::: + +For complex documents, you can nest objects (subdocuments) inside a document. + +```js +{ + name: { + first: "Thomas", + last: "Edison" + }, + invention: "Lightbulb", + birth: 1847 +} +``` + +In the example above, the `name` field is a subdocument embedded into a document. + +## Dot notation + +Dot notations `(.)` are used to reference a field in an embedded document or its index position in an array. + +### Arrays + +Dot notations can be used to specify or query an array by concatenating a dot `(.)` with the index position of the field. + +```js +'array_name.index' +``` + +:::note +When using dot notations, the field name of the array and the specified value must be enclosed in quotation marks. +::: + +For example, let's take the following array field in a document: + +```js +animals: ['dog', 'cat', 'fish', 'fox'] +``` + +To reference the fourth field in the array, use the dot notation `"animals.3"`. + +Here are more examples of dot notations on arrays: + +- [Query an array](basic-operations/read.md#retrieve-documents-containing-a-specific-value-in-an-array) +- [Update an array](basic-operations/update.md#update-an-array-element) + +### Embedded documents + +To reference or query a field in an embedded document, concatenate the name of the embedded document and the field name using the dot notation. + +```js +'embedded_document_name.field' +``` + +Take the following document, for example: + +```js +{ + name:{ + first: "Tom", + last: "Barry" + }, + contact:{ + address:{ + city: "Kent", + state: "Ohio" + }, + phone: "432-124-1234" + } +} +``` + +To reference the `city` field in the embedded document, use the dot notation `"contact.address.city"`. + +For dot notation examples on embedded documents, see here: + +- [Query an embedded document](basic-operations/read.md#query-on-an-embedded-or-nested-document) +- [Update an embedded document](basic-operations/update.md#update-an-embedded-document) + +## Collections + +Collections are a repository for documents. +To some extent, they are similar to tables in a relational database. +If a collection does not exist, FerretDB creates a new one when you insert documents for the first time. +A collection may contain one or more documents. +For example, the following collection contains three documents. + +```js +{ + Scientists: [ + { + first: 'Alan', + last: 'Turing', + born: 1912 + }, + { + first: 'Thomas', + last: 'Edison', + birth: 1847 + }, + { + first: 'Nikola', + last: 'Tesla', + birth: 1856 + } + ] +} +``` diff --git a/website/versioned_docs/version-v1.16/aggregation-operations/_category_.yml b/website/versioned_docs/version-v1.16/aggregation-operations/_category_.yml new file mode 100644 index 000000000000..f6e53577a0e8 --- /dev/null +++ b/website/versioned_docs/version-v1.16/aggregation-operations/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Aggregation Operations +position: 6 +link: + type: generated-index + slug: /aggregation-operations/ + description: > + This section details aggregation operations in FerretDB, including aggregation commands, stages, and operators diff --git a/website/versioned_docs/version-v1.16/aggregation-operations/aggregation-pipeline-and-commands.md b/website/versioned_docs/version-v1.16/aggregation-operations/aggregation-pipeline-and-commands.md new file mode 100644 index 000000000000..afacda117a23 --- /dev/null +++ b/website/versioned_docs/version-v1.16/aggregation-operations/aggregation-pipeline-and-commands.md @@ -0,0 +1,77 @@ +--- +sidebar_position: 1 +--- + +# Aggregation pipeline and commands + +Aggregation operations involve performing various operations on a large number of data records, such as data grouping, sorting, restructuring, or modifying. +These operations pass through one or more stages, which make up a pipeline. + +![aggregation stages](/img/docs/aggregation-stages.jpg) + +Each stage acts upon the returned documents of the previous stage, starting with the input documents. +As shown above, the documents pass through the pipeline with the result of the previous stage acting as input for the next stage, going from `$match` => `$group` => `$sort` stage. + +For example, insert the following documents in a `sales` collection: + +```js +db.sales.insertMany([ + { _id: 1, category: 'Electronics', price: 1000 }, + { _id: 2, category: 'Electronics', price: 800 }, + { _id: 3, category: 'Clothing', price: 30 }, + { _id: 4, category: 'Clothing', price: 50 }, + { _id: 5, category: 'Home', price: 1500 }, + { _id: 6, category: 'Home', price: 1200 }, + { _id: 7, category: 'Books', price: 20 }, + { _id: 8, category: 'Books', price: 40 } +]) +``` + +A typical aggregation pipeline would look like this: + +```js +db.sales.aggregate([ + { $match: { category: { $ne: 'Electronics' } } }, + { + $group: { + _id: '$category', + totalPrice: { $sum: '$price' }, + productCount: { $sum: 1 } + } + }, + { $sort: { totalPrice: -1 } } +]) +``` + +In the pipeline, the complex query is broken down into separate stages where the record goes through a series of transformations until it finally produces the desired result. +First, the `$match` stage filters out all documents where the `category` field is not `Electronics`. +Then, the `$group` stage groups the documents by their `category` and calculates the total price and product count for each of those category. +Finally, the `$sort` stage sorts the documents by the `totalPrice` field in descending order. + +So the above aggregation pipeline operation would return the following result: + +```json5 +[ + { _id: 'Home', totalPrice: 2700, productCount: 2 }, + { _id: 'Clothing', totalPrice: 80, productCount: 2 }, + { _id: 'Books', totalPrice: 60, productCount: 2 } +] +``` + +This section of the documentation will focus on [`aggregate` command](#aggregate-command), [aggregation stages](aggregation-stages.md), and aggregation operators. + +## `aggregate` command + +The aggregation command `aggregate` is a top-level command used for aggregating data across various pipeline stages. + +The command is used for performing aggregation operations on a collection and lets you specify aggregation operations in a pipeline consisting of one or more stages and operators for transforming and analyzing data, such as grouping, filtering, sorting, projecting, and calculating aggregates. + +```js +// Aggregation pipeline to perform aggregation operations on a collection +db.collection.aggregate([ + // Stage 1: Matching documents based on a specific field and value + { $match: { field: value } }, + // Stage 2: Grouping documents by the "category" field and calculating the sum of the "quantity" field + { $group: { _id: '$category', total: { $sum: '$quantity' } } } +]) +``` diff --git a/website/versioned_docs/version-v1.16/aggregation-operations/aggregation-stages.md b/website/versioned_docs/version-v1.16/aggregation-operations/aggregation-stages.md new file mode 100644 index 000000000000..1b27aa0a1c30 --- /dev/null +++ b/website/versioned_docs/version-v1.16/aggregation-operations/aggregation-stages.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 2 +--- + +# Aggregation stages + +Aggregation stages are a series of one or more processes in a pipeline that acts upon the returned result of the previous stage, starting with the input documents. + +| Supported aggregation stages | Description | +| ---------------------------- | ----------------------------------------------------------------------------------------------------- | +| `$count` | Returns the count of all matched documents in a specified query | +| `$group` | Groups documents based on specific value or expression and returns a single document for each group | +| `$limit` | Limits specific documents and passes the rest to the next stage | +| `$match` | Acts as a `find` operation by only returning documents that match a specified query to the next stage | +| `$project` | Specifies the fields in a document to pass to the next stage in the pipeline | +| `$skip` | Skips a specified `n` number of documents and passes the rest to the next stage | +| `$sort` | Sorts and returns all the documents based on a specified order | +| `$unset` | Specifies the fields to be removed/excluded from a document | +| `$unwind` | Deconstructs and returns a document for every element in an array field | diff --git a/website/versioned_docs/version-v1.16/basic-operations/_category_.yml b/website/versioned_docs/version-v1.16/basic-operations/_category_.yml new file mode 100644 index 000000000000..0efa62204a79 --- /dev/null +++ b/website/versioned_docs/version-v1.16/basic-operations/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Basic CRUD Operations +position: 4 +link: + type: generated-index + slug: /basic-operations/ + description: > + Perform basic CRUD operations using FerretDB diff --git a/website/versioned_docs/version-v1.16/basic-operations/create.md b/website/versioned_docs/version-v1.16/basic-operations/create.md new file mode 100644 index 000000000000..d524b993bab2 --- /dev/null +++ b/website/versioned_docs/version-v1.16/basic-operations/create.md @@ -0,0 +1,80 @@ +--- +sidebar_position: 2 +--- + +# Insert operation + +The insert operation adds a new document to a collection. + +## Insert a single document + +The `insertOne()` command is used to add a single document into a collection, using this syntax format: + +```js +db.collection.insertOne({field1: value1, field2: value2,.... fieldN: valueN}) +``` + +The example below depicts how a single document can be added to a collection. +If a collection does not exist, the insert command automatically creates one. + +```js +db.scientists.insertOne({ + name: { + firstname: 'Thomas', + lastname: 'Edison' + }, + born: 1847, + invention: 'lightbulb' +}) +``` + +If the operation is successful, you will get a response with acknowledged set to true, and the autogenerated ObjectId of the document that looks like this: + +```js +{ + acknowledged: true, + insertedId: ObjectId("6346fcafd7a4a1b0b38eb2db") +} +``` + +## Insert multiple documents at once + +A collection can contain multiple documents. +Using the `insertMany()` command, you can add multiple documents to a collection at once. + +```js +db.collection_name.insertMany([{ document1 }, { document2 }, ...{ documentN }]) +``` + +The following example shows how to insert multiple documents into a collection: + +```js +db.scientists.insertMany([ + { + name: { + firstname: 'Alan', + lastname: 'Turing' + }, + born: 1912, + invention: 'Turing Machine' + }, + { + name: { + firstname: 'Graham', + lastname: 'Bell' + }, + born: 1847, + invention: 'telephone' + }, + { + name: { + firstname: 'Ada', + lastname: 'Lovelace' + }, + born: 1815, + invention: 'computer programming' + } +]) +``` + +You can retrieve all the documents in the collection with this command: `db.scientists.find({})` diff --git a/website/versioned_docs/version-v1.16/basic-operations/delete.md b/website/versioned_docs/version-v1.16/basic-operations/delete.md new file mode 100644 index 000000000000..50bda975115a --- /dev/null +++ b/website/versioned_docs/version-v1.16/basic-operations/delete.md @@ -0,0 +1,88 @@ +--- +sidebar_position: 5 +--- + +# Delete operation + +The delete operation removes a document from the database when a given query is met. +Two methods for deleting documents in a collection include `deleteOne()` and `deleteMany()`. + +## Delete a single document + +The `deleteOne()` method removes a single document (the first document that matches the query parameter) completely from the collection. + +```js +db.collection.deleteOne({}) +``` + +Insert the following list of documents: + +```js +db.scientists.insertMany([ + { + firstname: 'Thomas', + lastname: 'Edison', + born: 1847, + invention: 'LightBulb', + nobel: true + }, + { + firstname: 'Graham', + lastname: 'Bell', + born: 1847, + invention: 'telephone', + nobel: false + }, + { + firstname: 'Nikola', + lastname: 'Tesla', + born: 1856, + invention: 'Tesla coil', + nobel: false + }, + { + firstname: 'Ada', + lastname: 'Lovelace', + born: 1815, + invention: 'Computer programming', + nobel: false + } +]) +``` + +This operation returns a response showing `acknowledged` as `true` and the `ObjectId` of the four inserted documents: + +```js +{ + acknowledged: true, + insertedIds: { + '0': ObjectId("63470121d7a4a1b0b38eb2df"), + '1': ObjectId("63470121d7a4a1b0b38eb2e0"), + '2': ObjectId("63470121d7a4a1b0b38eb2e1"), + '3': ObjectId("63470121d7a4a1b0b38eb2e2") + } +} +``` + +Next, delete a document from the collection where the field `nobel` is set to false. + +```js +db.scientists.deleteOne({ nobel: false }) +``` + +This operation returns a response that shows that a single document was deleted from the collection. + +```js +{ acknowledged: true, deletedCount: 1 } +``` + +## Deletes multiple documents + +To delete multiple documents at once, use the `deleteMany()` method. +Using the same record from earlier, let's delete all the documents with `nobel` set to false. + +```js +db.scientists.deleteMany({ nobel: false }) +``` + +This command removes all the documents in the collection that matches the query. diff --git a/website/versioned_docs/version-v1.16/basic-operations/index.md b/website/versioned_docs/version-v1.16/basic-operations/index.md new file mode 100644 index 000000000000..a125d1eaa0a4 --- /dev/null +++ b/website/versioned_docs/version-v1.16/basic-operations/index.md @@ -0,0 +1,44 @@ +--- +sidebar_position: 1 +slug: /crud-operations/ +--- + +# Performing CRUD operations + +CRUD (Create, Read, Update, and Delete) operations in FerretDB use the same protocol and drivers as MongoDB. + +## Create operations in FerretDB + +The create operation adds a new document to a collection. +If the collection does not exist, this operation will create it. +The following methods are available for adding documents to a collection: + +[`db.collection.insertOne()`](create.md#insert-a-single-document), +[`db.collection.insertMany()`](create.md#insert-multiple-documents-at-once) + +## Read operations in FerretDB + +The read operation retrieves document records in a collection. +You can also filter the documents by targeting specific criteria for retrieval. +The following commands are used to retrieve documents from a collection: + +[`db.collection.find()`](read.md#retrieve-all-documents-in-a-collection), [`db.collection.findOne()`](read.md#retrieve-a-single-document) + +The read operation can also retrieve subdocuments that are nested within a document. + +## Update operations in FerretDB + +The update operation modifies document records in a collection. +It changes existing documents in a collection according to the query criteria. +The following update operations are supported: + +[`db.collection.updateOne()`](update.md#update-a-single-document), [`db.collection.updateMany()`](update.md#update-many-documents), [`db.collection.replaceOne()`](update#replace-a-document) + +## Delete operations in FerretDB + +The delete operation removes document records from a collection. +The following delete operations are supported: + +[`db.collection.deleteOne()`](delete.md#delete-a-single-document), [`db.collection.deleteMany()`](delete.md#deletes-multiple-documents) + +Similar to the update operation, this operation retrieves documents matching specific criteria in a collection and deletes them. diff --git a/website/versioned_docs/version-v1.16/basic-operations/read.md b/website/versioned_docs/version-v1.16/basic-operations/read.md new file mode 100644 index 000000000000..bc43096aaa90 --- /dev/null +++ b/website/versioned_docs/version-v1.16/basic-operations/read.md @@ -0,0 +1,197 @@ +--- +sidebar_position: 3 +--- + +# Read operation + +The read operation retrieves documents in a collection. +You can either retrieve all the documents in a collection, or only the documents that match a given query parameter. + +## Retrieve a single document + +The `findOne()` command retrieves a single document from a collection. + +First, populate the database with a new collection containing a list of documents. + +```js +db.scientists.insertMany([ + { + name: { + firstname: 'Alan', + lastname: 'Turing' + }, + born: 1912, + invention: 'Turing Machine' + }, + { + name: { + firstname: 'Graham', + lastname: 'Bell' + }, + born: 1847, + invention: 'telephone' + }, + { + name: { + firstname: 'Ada', + lastname: 'Lovelace' + }, + born: 1815, + invention: 'computer programming' + } +]) +``` + +Run the following `findOne()` operation to retrieve a single document from the collection: + +```js +db.scientists.findOne({ invention: 'Turing Machine' }) +``` + +## Retrieve all documents in a collection + +The `find()` command is used for retrieving all the documents in a collection. + +```js +db.collection.find() +``` + +Run `db.scientists.find()` to see the complete list of documents in the collection. + +### Retrieve documents based on a specific query + +Using the `find()` command, you can also filter a collection for only the documents that match the provided query. +For example, find the document with the field `born` set as 1857. + +```js +db.scientists.find({ born: 1857 }) +``` + +### Retrieve documents using operator queries + +The operator syntax allows users to query and retrieve a document. +There are several operator methods that you can use, such as `$gt` or `$lt`. +For example, to find the list of scientists born after the 1900s, we'll need the `$gt` operator: + +```js +db.scientists.find({ born: { $gt: 1900 } }) +``` + +Here is a list of the most commonly used operators. + +`$gt`: selects records that are greater than a specific value + +`$lt`: selects records that are less than a specific value + +`$gte`: selects records greater or equal to a specific value + +`$lte`: selects records less than or equal to a specific value + +`$in`: selects any record that contains any of the items present in a defined array + +`$nin`: selects any record that does not contain any of the items in a defined array + +`$ne`: selects records that are not equal to a specific value + +`$eq`: select records that are equal to a specific value + +### Retrieve documents containing a specific value in an array + +Insert the following documents into an `employees` collection using this command: + +```js +db.employees.insertMany([ + { + name: { + first: 'Earl', + last: 'Thomas' + }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + name: { + first: 'Sam', + last: 'Johnson' + }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + name: { + first: 'Clarke', + last: 'Dane' + }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +]) +``` + +To retrieve all documents with a specific array field and value (`catalog: "printer"`), run the following command: + +```js +db.employees.find({ catalog: 'printer' }) +``` + +The response displays all the retrieved documents: + +```json5 +[ + { + _id: ObjectId("636b39f80466c61a229bbf9b"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("636b3b0e0466c61a229bbf9d"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +### Retrieve documents in an array using dot notation + +To retrieve all documents containing a specific value in an array, use dot notation to reference its position in the `employees` collection. +The following command retrieves all documents containing `"blender"` in the third field of an array: + +```js +db.employees.find({ 'catalog.2': 'blender' }) +``` + +The document that matches the array query is displayed in the response: + +```json5 +[ + { + _id: ObjectId("636b3b0e0466c61a229bbf9c"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + } +] +``` + +### Query on an embedded or nested document + +To query on an embedded document, use dot notation to specify the fields. +The following command queries on the embedded document in the`employees` collection: + +```js +db.employees.find({ 'name.first': 'Clarke' }) +``` diff --git a/website/versioned_docs/version-v1.16/basic-operations/update.md b/website/versioned_docs/version-v1.16/basic-operations/update.md new file mode 100644 index 000000000000..0030e1e69053 --- /dev/null +++ b/website/versioned_docs/version-v1.16/basic-operations/update.md @@ -0,0 +1,205 @@ +--- +sidebar_position: 4 +--- + +# Update operation + +The update operation modifies a document record in a collection, based on a given query parameter and update. +FerretDB supports update operators, such as `$set` and `$setOnInsert` to update documents in a record. + +At present, FerretDB currently supports the following update operators: + +| Operator name | Description | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `$set` | Assigns the value for an updated field to the document. | +| `$setOnInsert` | Specifies the value of a field when an update operation results in the addition of a document. However, there is no effect when it modifies an existing document. | +| `$unset` | Removes a specific field from a document. | +| `$pop` | In an array, this operator removes the first or last item. | + +## Update a single document + +Use the `updateOne()` method to update a single document in a collection. +This operation filters a collection using a query parameter, and updates given fields within that document. + +```js +db.collection.updateOne({}, {$set: {}}) +``` + +First, populate the database with a collection containing a list of documents. + +```js +db.scientists.insertMany([ + { + firstname: 'Thomas', + lastname: 'Edison', + born: 1847, + invention: 'LightBulb', + nobel: true + }, + { + firstname: 'Graham', + lastname: 'Bell', + born: 1847, + invention: 'telephone', + nobel: false + }, + { + firstname: 'Nikola', + lastname: 'Tesla', + born: 1856, + invention: 'Tesla coil', + nobel: false + }, + { + firstname: 'Ada', + lastname: 'Lovelace', + born: 1815, + invention: 'Computer programming', + nobel: false + } +]) +``` + +Using the document record in the collection, update the document where `firstname` is "Graham", and set it as "Alexander Graham". +The `updateOne()` operation will only affect the first document that's retrieved in the collection. + +```js +db.scientists.updateOne( + { + firstname: 'Graham' + }, + { + $set: { + firstname: 'Alexander Graham' + } + } +) +``` + +## Replace a document + +Besides updating a document, you can replace it completely using the `replaceOne()` method. + +```js +db.scientists.replaceOne( + { + lastname: 'Bell' + }, + { + lastname: 'Einstein', + firstname: 'Albert', + born: 1879, + invention: 'Photoelectric effect', + nobel: true + } +) +``` + +## Update many documents + +Using the `updateMany()` command, you can modify many documents at once. +In the example below, where `nobel` is set as false, update and set to true. + +```js +db.scientists.updateMany({ nobel: false }, { $set: { nobel: true } }) +``` + +This operation updates all the documents where the field `nobel` was previously false. + +## Update an array element + +The following update example uses the `employees` collection. +To populate the collection, run the following in your terminal: + +```js +db.employees.insertMany([ + { + name: { + first: 'Earl', + last: 'Thomas' + }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + name: { + first: 'Sam', + last: 'Johnson' + }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + name: { + first: 'Clarke', + last: 'Dane' + }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +]) +``` + +The following command will query and update the `catalog` array in the `employee` collection using dot notation. +The command will query the second field of the array in every document for `"pencil"`, and when there is a match, updates the first element of the array. + +```js +db.employees.updateMany( + { + 'catalog.1': 'pencils' + }, + { + $set: { + 'catalog.0': 'ruler' + } + } +) +``` + +The response from the command: + +```js +{ + acknowledged: true, + insertedId: null, + matchedCount: 1, + modifiedCount: 1, + upsertedCount: 0 +} +``` + +## Update an embedded document + +To update an embedded document, use dot notation to specify the fields to modify. +The following operation updates any embedded document that matches the specified query in the `employees` collection. + +```js +db.employees.updateMany( + { + 'name.first': 'Clarke' + }, + { + $set: { + 'name.last': 'Elliot' + } + } +) +``` + +The following response from the command shows that a single document matching the query was updated: + +```js +{ + acknowledged: true, + insertedId: null, + matchedCount: 1, + modifiedCount: 1, + upsertedCount: 0 +} +``` diff --git a/website/versioned_docs/version-v1.16/configuration/_category_.yml b/website/versioned_docs/version-v1.16/configuration/_category_.yml new file mode 100644 index 000000000000..2524e7b4b4e1 --- /dev/null +++ b/website/versioned_docs/version-v1.16/configuration/_category_.yml @@ -0,0 +1,10 @@ +--- +label: Configuration +position: 10 +link: + type: generated-index + slug: /configuration/ + description: > + This configuration section provides guidance on setting up and customizing + the FerretDB environment through various flags, variables, and operation + modes diff --git a/website/versioned_docs/version-v1.16/configuration/flags.md b/website/versioned_docs/version-v1.16/configuration/flags.md new file mode 100644 index 000000000000..aaaca18df10d --- /dev/null +++ b/website/versioned_docs/version-v1.16/configuration/flags.md @@ -0,0 +1,114 @@ +--- +sidebar_position: 1 +--- + +# Configuration flags + +FerretDB provides numerous configuration flags you can customize to suit your needs and environment. +You can always see the complete list by using `--help` flag. +To make user experience cloud native, every flag has its environment variable equivalent. +There is no configuration file. + +:::info +Some default values are overridden in [our Docker image](../quickstart-guide/docker.md). +::: + + + + + + + +## General + +| Flag | Description | Environment Variable | Default Value | +| -------------- | ----------------------------------------------------------------- | -------------------- | ------------------------------ | +| `-h`, `--help` | Show context-sensitive help | | false | +| `--version` | Print version to stdout and exit | | false | +| `--handler` | Backend handler | `FERRETDB_HANDLER` | `pg` (PostgreSQL) | +| `--mode` | [Operation mode](operation-modes.md) | `FERRETDB_MODE` | `normal` | +| `--state-dir` | Path to the FerretDB state directory
(set to `-` to disable) | `FERRETDB_STATE_DIR` | `.`
(`/state` for Docker) | + +## Interfaces + +| Flag | Description | Environment Variable | Default Value | +| ------------------------ | ------------------------------------------------------------------------------------- | ------------------------------- | -------------------------------------------- | +| `--listen-addr` | Listen TCP address | `FERRETDB_LISTEN_ADDR` | `127.0.0.1:27017`
(`:27017` for Docker) | +| `--listen-unix` | Listen Unix domain socket path | `FERRETDB_LISTEN_UNIX` | | +| `--listen-tls` | Listen TLS address (see [here](../security/tls-connections.md)) | `FERRETDB_LISTEN_TLS` | | +| `--listen-tls-cert-file` | TLS cert file path | `FERRETDB_LISTEN_TLS_CERT_FILE` | | +| `--listen-tls-key-file` | TLS key file path | `FERRETDB_LISTEN_TLS_KEY_FILE` | | +| `--listen-tls-ca-file` | TLS CA file path | `FERRETDB_LISTEN_TLS_CA_FILE` | | +| `--proxy-addr` | Proxy address | `FERRETDB_PROXY_ADDR` | | +| `--proxy-tls-cert-file` | Proxy TLS cert file path | `FERRETDB_PROXY_TLS_CERT_FILE` | | +| `--proxy-tls-key-file` | Proxy TLS key file path | `FERRETDB_PROXY_TLS_KEY_FILE` | | +| `--proxy-tls-ca-file` | Proxy TLS CA file path | `FERRETDB_PROXY_TLS_CA_FILE` | | +| `--debug-addr` | Listen address for HTTP handlers for metrics, pprof, etc
(set to `-` to disable) | `FERRETDB_DEBUG_ADDR` | `127.0.0.1:8088`
(`:8088` for Docker) | + +## Backend handlers + + + +### PostgreSQL + +[PostgreSQL backend](../understanding-ferretdb.md#postgresql) can be enabled by +`--handler=pg` flag or `FERRETDB_HANDLER=pg` environment variable. + +| Flag | Description | Environment Variable | Default Value | +| ------------------ | ------------------------------- | ------------------------- | ------------------------------------ | +| `--postgresql-url` | PostgreSQL URL for 'pg' handler | `FERRETDB_POSTGRESQL_URL` | `postgres://127.0.0.1:5432/ferretdb` | + +FerretDB uses [pgx v5](https://github.com/jackc/pgx) library for connecting to PostgreSQL. +Supported URL parameters are documented there: + +- https://pkg.go.dev/github.com/jackc/pgx/v5/pgconn#ParseConfig +- https://pkg.go.dev/github.com/jackc/pgx/v5#ParseConfig +- https://pkg.go.dev/github.com/jackc/pgx/v5/pgxpool#ParseConfig + +Additionally: + +- `pool_max_conns` parameter is set to 50 if it is unset in the URL; +- `application_name` is always set to "FerretDB"; +- `timezone` is always set to "UTC". + +### SQLite + +[SQLite backend](../understanding-ferretdb.md#sqlite) can be enabled by +`--handler=sqlite` flag or `FERRETDB_HANDLER=sqlite` environment variable. + +| Flag | Description | Environment Variable | Default Value | +| -------------- | ------------------------------------------- | --------------------- | ------------------------------------------------- | +| `--sqlite-url` | SQLite URI (directory) for 'sqlite' handler | `FERRETDB_SQLITE_URL` | `file:data/` `.`
(`file:/state/` for Docker) | + +FerretDB uses [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) library for accessing SQLite database files. +Supported URL parameters are documented there: + +- https://www.sqlite.org/uri.html +- https://pkg.go.dev/modernc.org/sqlite#Driver.Open +- https://www.sqlite.org/pragma.html + +Additionally: + +- `_pragma=auto_vacuum(none)` parameter is set if that PRAGMA is not present; +- `_pragma=busy_timeout(10000)` parameter is set if that PRAGMA is not present; +- `_pragma=journal_mode(wal)` parameter is set if that PRAGMA is not present. + +One difference is that URI should point to the existing directory (with absolute or relative path), not to a single database file. +That allows FerretDB to work with multiple databases. + +In-memory SQLite databases are fully supported. +In that case, the URI should still point to the existing directory (that will be unused). +For example: `file:./?mode=memory`. + +## Miscellaneous + +| Flag | Description | Environment Variable | Default Value | +| --------------------- | ------------------------------------------------- | ----------------------- | ------------- | +| `--log-level` | Log level: 'debug', 'info', 'warn', 'error' | `FERRETDB_LOG_LEVEL` | `info` | +| `--[no-]log-uuid` | Add instance UUID to all log messages | `FERRETDB_LOG_UUID` | | +| `--[no-]metrics-uuid` | Add instance UUID to all metrics | `FERRETDB_METRICS_UUID` | | +| `--telemetry` | Enable or disable [basic telemetry](telemetry.md) | `FERRETDB_TELEMETRY` | `undecided` | + + + + diff --git a/website/versioned_docs/version-v1.16/configuration/observability.md b/website/versioned_docs/version-v1.16/configuration/observability.md new file mode 100644 index 000000000000..aefe006758db --- /dev/null +++ b/website/versioned_docs/version-v1.16/configuration/observability.md @@ -0,0 +1,45 @@ +--- +sidebar_position: 3 +description: Observability +--- + +# Observability + +## Logging + +The log level and format can be adjusted by [configuration flags](flags.md#miscellaneous). + +Please note that the structured log format is not stable yet; field names and formatting of values might change in minor releases. + +### Docker logs + +If Docker was launched with [our quick local setup with Docker Compose](../quickstart-guide/docker.md#setup-with-docker-compose), +the following command can be used to fetch the logs. + +```sh +docker compose logs ferretdb +``` + +Otherwise, you can check a list of running Docker containers with `docker ps` +and get logs with `docker logs`: + +```sh +$ docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +13db4c8800d3 postgres "docker-entrypoint.s…" About a minute ago Up 59 seconds 5432/tcp my-postgres +44fe6f4c3527 ghcr.io/ferretdb/ferretdb "/ferretdb" About a minute ago Up 59 seconds 8080/tcp, 27018/tcp, 0.0.0.0:27017->27017/tcp my-ferretdb + +$ docker logs my-ferretdb +``` + +### Binary executable logs + +FerretDB writes logs to the standard error (`stderr`) stream. + +## Metrics + +FerretDB exposes metrics in Prometheus format on the debug handler on `http://127.0.0.1:8088/debug/metrics` by default. +There is no need to use an external exporter. +The host and port can be changed with [`--debug-addr` flag](flags.md#interfaces). + +Please note that the set of metrics is not stable yet; metric and label names and formatting of values might change in minor releases. diff --git a/website/versioned_docs/version-v1.16/configuration/operation-modes.md b/website/versioned_docs/version-v1.16/configuration/operation-modes.md new file mode 100644 index 000000000000..7d3e5c587044 --- /dev/null +++ b/website/versioned_docs/version-v1.16/configuration/operation-modes.md @@ -0,0 +1,49 @@ +--- +sidebar_position: 2 +slug: /configuration/operation-modes/ # referenced in README.md +--- + +# Operation modes + +To simplify the development and debugging of FerretDB, we support different operation modes. +Operation modes specify how FerretDB handles incoming requests. +They are useful for testing, debugging, or bug reporting. + +You can specify modes by using the `--mode` flag or `FERRETDB_MODE` variable, +which accept following types of values: `normal`, `proxy`, `diff-normal`, `diff-proxy`. + +By default FerretDB always run on `normal` mode, which means that all client requests +are processed only by FerretDB and returned to the client. + +## Proxy + +Proxy is another MongoDB-compatible database, accessible from the machine. +You can specify its connection URL with `--proxy-addr` flag or with the `FERRETDB_PROXY_ADDR` variable. + +To forward all requests to proxy and return them to the client, use `proxy` operation mode. + +## Diff modes + +Diff modes (`diff-normal`, `diff-proxy`) forward requests to both databases, and log the difference between them. + +The `diff-normal` afterwards returns the response from FerretDB and `diff-proxy` - from the specified proxy handler. + +Example diff output: + +```diff +Header diff: +--- res header ++++ proxy header +@@ -1 +1 @@ +-length: 63, id: 14, response_to: 24, opcode: OP_MSG ++length: 64, id: 229, response_to: 24, opcode: OP_MSG + +Body diff: +--- res body ++++ proxy body +@@ -10,3 +10,3 @@ + ], +- "you": "127.0.0.1:57079", ++ "you": "172.19.0.1:59824", + "ok": { +``` diff --git a/website/versioned_docs/version-v1.16/contributing/_category_.yml b/website/versioned_docs/version-v1.16/contributing/_category_.yml new file mode 100644 index 000000000000..1fd6b7a57f8b --- /dev/null +++ b/website/versioned_docs/version-v1.16/contributing/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Contributing to FerretDB +position: 15 +link: + type: generated-index + slug: /contributing/ + description: > + Follow our guide on how to contribute to FerretDB diff --git a/website/versioned_docs/version-v1.16/contributing/index.md b/website/versioned_docs/version-v1.16/contributing/index.md new file mode 100644 index 000000000000..b405171cc58c --- /dev/null +++ b/website/versioned_docs/version-v1.16/contributing/index.md @@ -0,0 +1,48 @@ +--- +sidebar_position: 1 +slug: /how-to-contribute/ +--- + +# How to contribute to FerretDB + +FerretDB is an open source project and everyone – developers and non-developers – is welcome to contribute. +If you're interested in contributing to FerretDB projects, this documentation will help you get started. + +Here are some of the current FerretDB projects that you can fork and contribute to: + +- [FerretDB](https://github.com/FerretDB/FerretDB): This is the main repository of FerretDB. +- [dance](https://github.com/FerretDB/dance): This repository contains the FerretDB integration testing tool. +- [github-actions](https://github.com/FerretDB/github-actions): This repository houses our shared GitHub Actions for FerretDB, dance, and other repositories. + +For those taking their first steps in contributing to an open source project. +Please take a look at this post on [how to contribute to open source software](https://blog.ferretdb.io/how-to-contribute-to-open-source-2022/). + +## Get started + +You don't have to be a developer to contribute to FerretDB projects, you can even get started by helping us improve this documentation. +If you have any questions or suggestions on how we can improve, kindly join our [community](/#community). +We appreciate your feedback. + +## Contributing to this documentation + +If you find anything confusing or missing in the documentation, click the "Edit this page" link at the bottom of almost every page in the documentation. +More information on contributing to the documentation can be found [here](https://github.com/FerretDB/FerretDB/blob/main/CONTRIBUTING.md#contributing-documentation). + +## Contributing to the FerretDB repository + +- To contribute to this [FerretDB project](https://github.com/FerretDB/FerretDB/), please read the [CONTRIBUTING.md](https://github.com/FerretDB/FerretDB/blob/main/CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](https://github.com/FerretDB/FerretDB/blob/main/CODE_OF_CONDUCT.md) guideline to know more. +- Is everything working as it should? + If not, please let us know by [creating an issue](https://github.com/FerretDB/FerretDB/issues/new/choose). + You can create issues for bugs, documentation, features, or enhancements. +- You can identify issues you would like to work on by looking at the [open issues](https://github.com/FerretDB/FerretDB/issues) for this repository. +- The most straightforward way to start contributing to this repository is to select issues that are labeled [good-first-issues](https://github.com/FerretDB/FerretDB/contribute) + +## Contributing to dance + +- To start contributing to the [dance repository](https://github.com/FerretDB/dance) for integration testing, follow the guidelines in the [CONTRIBUTING.md](https://github.com/FerretDB/dance/blob/main/CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](https://github.com/FerretDB/dance/blob/main/CODE_OF_CONDUCT.md) files. +- Looking for something to work on? + Check out the [open issues](https://github.com/FerretDB/dance/issues) for this repository. + +## Contributing to github-actions + +- To contribute to our [github-actions repository](https://github.com/FerretDB/github-actions/), please go through the instructions in the [CONTRIBUTING.md](https://github.com/FerretDB/github-actions/blob/main/CONTRIBUTING.md) file. diff --git a/website/versioned_docs/version-v1.16/contributing/writing-guide.md b/website/versioned_docs/version-v1.16/contributing/writing-guide.md new file mode 100644 index 000000000000..de980c209aaf --- /dev/null +++ b/website/versioned_docs/version-v1.16/contributing/writing-guide.md @@ -0,0 +1,144 @@ +--- +sidebar_position: 99 +unlisted: true # linked from CONTRIBUTING.md +--- + +# Writing guide + +## Front matter + +The front matter represents the metadata for each page. +It is written at the top of each page and must be enclosed by `---` on both sides. + +Example: + +```yaml +--- +sidebar_position: 1 +description: How to write documentation +--- +``` + +Learn more about [front matter in Docusaurus](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-docs#markdown-front-matter). + +## Names and URLs + +Use `kebab-case-with-dashes` instead of `snake_case_with_underscores` or spaces +for file names, directory names, and slugs because URL paths typically use dashes. + +Ensure that the file name/URL path matches the title of the page. +For example, if the title of your page is "Getting Started", then the file name/URL path should also be "getting-started" to maintain consistency. +The `slug` field should be the same as the file name. +Only use a different `slug` field in some special cases, such as for backward compatibility with existing links. + +## Sidebar position + +Use the `sidebar_position` in the front matter to set the order of the pages in the sidebar. +Please ensure that the `sidebar_position` is unique for each page in that directory. +For example, if there are several pages in the folder "Getting Started", let `sidebar_position` equal "1", "2", "3", "4", and so on to avoid duplication. + +## Headers + +Use sentence case for headers: `### Some header with URL`, not `### Some Header With URL`. + +## Links + +Please use relative `.md` file paths for links. +It is required for [documentation versioning](https://docusaurus.io/docs/versioning#link-docs-by-file-paths). + +Examples: + +To link to a file in the same directory, use the file name. + +- `[file in the same directory](writing-guide.md)` + +To link to file in a different directory, specify the relative file path. + +- `[file in a different directory](../basic-operations/read.md)`. + +## Images + +Please store all images under `blog` or `docs` in the `static/img` folder. + +Also, you can collate images for a specific blog post inside a single folder. +For partner blog posts, store related images in the same folder, as `/img/blog/partner-name/image.png`. + +Otherwise, name the folder appropriately using the `YYYY-MM-DD` format, for example, a typical path for an image will be `/img/blog/2023-01-01/ferretdb-image.jpg`. + +### Alt text + +Please remember to add an alternate text for images. +The alt text should provide a description of the image for the user. +When you add a banner image, please use the title of the article as the alt text. + +### Image names + +Use of two or three descriptive words written in `kebab-case-with-dashes` as the names for the images. +For example, _ferretdb-queries.jpg_. + +### Image links + +Use Markdown syntax for images with descriptive alt texts and the path. +All assets (images, gifs, videos, etc.) relating to FerretDB documentation and blog are in the `static/img/` folder. +Rather than use relative paths, we strongly suggest the following approach, since our content engine renders all images directly from the `img` folder. + +`![FerretDB logo](/img/logo-dark.png)`. + +## Code blocks + +Always specify the language in Markdown code blocks. + +For MongoDB shell commands, use `js` language. +Our tooling will automatically reformat those blocks. + +```js +db.league.find({ club: 'PSG' }) +``` + +For MongoDB shell results, use `json5` language and copy&paste the output as-is, +with unquoted field names, single quotes for strings, without trailing commas, etc. +Our tooling will not reformat those blocks. + +```json5 +[ + { + _id: ObjectId("63109e9251bcc5e0155db0c2"), + club: 'PSG', + points: 30, + average_age: 30, + discipline: { red: 5, yellow: 30 }, + qualified: false + } +] +``` + +Use `sql` for SQL queries. +Use `text` for the `psql` output and in other cases. + +```sql +SELECT _jsonb FROM "test"."_ferretdb_database_metadata" WHERE ((_jsonb->'_id')::jsonb = '"customers"'); +``` + +```text + _jsonb ---------------------------------------------------------------------------------------------------------------------------------------------- + {"$s": {"p": {"_id": {"t": "string"}, "table": {"t": "string"}}, "$k": ["_id", "table"]}, "_id": "customers", "table": "customers_c09344de"} +``` + +```text +ferretdb=# \d test._ferretdb_settings + Table "test._ferretdb_settings" + Column | Type | Collation | Nullable | Default +----------+-------+-----------+----------+--------- + settings | jsonb | | | + +ferretdb=# SELECT settings FROM test._ferretdb_settings; + settings +-------------------------------------------------------------------------------------------------- + {"$k": ["collections"], "collections": {"$k": ["groceries"], "groceries": "groceries_6a5f9564"}} +(1 row) +``` + +## Terminologies + +To be sure that you're using the right descriptive term, please check our [glossary page](../reference/glossary.md) for relevant terms and terminologies about FerretDB. +If the word is not present in the glossary page, please feel free to ask on Slack or in the blog post issue. diff --git a/website/versioned_docs/version-v1.16/diff.md b/website/versioned_docs/version-v1.16/diff.md new file mode 100644 index 000000000000..a19fdd0faba3 --- /dev/null +++ b/website/versioned_docs/version-v1.16/diff.md @@ -0,0 +1,32 @@ +--- +sidebar_position: 11 +slug: /diff/ # referenced in README.md and beacon +--- + +# Known differences + + + +1. FerretDB uses the same protocol error names and codes, but the exact error messages may be different in some cases. +2. FerretDB does not support NUL (`\0`) characters in strings. +3. FerretDB does not support nested arrays. +4. FerretDB converts `-0` (negative zero) to `0` (positive zero). +5. Document restrictions: + - document keys must not contain `.` sign; + - document keys must not start with `$` sign; + - document fields of double type must not contain `Infinity`, `-Infinity`, or `NaN` values. +6. When insert command is called, insert documents must not have duplicate keys. +7. Update command restrictions: + - update operations producing `Infinity`, `-Infinity`, or `NaN` are not supported. +8. Database and collection names restrictions: + - name cannot start with the reserved prefix `_ferretdb_`; + - database name must not include non-latin letters; + - collection name must be valid UTF-8 characters; +9. FerretDB offers the same validation rules for the `scale` parameter in both the `collStats` and `dbStats` commands. + If an invalid `scale` value is provided in the `dbStats` command, the same error codes will be triggered as with the `collStats` command. + +If you encounter some other difference in behavior, +please [join our community](/#community) to report a problem. diff --git a/website/versioned_docs/version-v1.16/indexes.md b/website/versioned_docs/version-v1.16/indexes.md new file mode 100644 index 000000000000..37f5e2e170c4 --- /dev/null +++ b/website/versioned_docs/version-v1.16/indexes.md @@ -0,0 +1,140 @@ +--- +sidebar_position: 8 +--- + +# Indexes + +Indexes are essential in improving query performance by enabling fast retrieval of relevant documents when querying large collections. + +Indexes in FerretDB are created based on a specific field(s) within documents. +Creating an index involves having a data structure that maps the values in the indexed fields to the locations of the related documents, making it possible to retrieve documents more quickly based on those fields. + +## How to create indexes + +Use the `createIndexes()` command to create an index on a collection. +You can use the `createIndex()` method to call the `createIndexes()` command. + +The `createIndexes()` command takes two arguments: a document containing the index key (fields to index and direction - either ascending or descending), and an optional document specifying the index options. + +You can create single field indexes or compound indexes. + +### Single field indexes + +Suppose a `products` collection contains the following documents: + +```json5 +{ _id: 1, name: "iPhone 12", category: "smartphone", price: 799 } +{ _id: 2, name: "iPad Pro", category: "tablet", price: 999 } +{ _id: 3, name: "Galaxy S21", category: "smartphone", price: 699 } +{ _id: 4, name: "MacBook Pro", category: "laptop", price: 1299 } +``` + +Here's an example of the `createIndex` method to create an index on the `price` field of a `products` collection: + +```js +db.products.createIndex({ price: 1 }) +``` + +This creates an ascending index on the `price` field. + +:::note +`1` specifies the index direction for ascending order. +If it's `-1`, it specifies a descending order direction for the index. +::: + +### Compound indexes + +For compound indexes, you can create an index key combining multiple fields together as a key. +Below is an example of a compound index that uses `price` and `category` fields +from the `products` collection as the index key: + +```js +db.products.createIndex({ price: 1, category: 1 }) +``` + +### Unique indexes + +You can create unique indexes to ensure that the indexed fields do not contain duplicate values. +To create a unique index, set the `unique` option as `true` when calling `createIndexes()` command. + +Below is an example of a unique index for the `name` field from the `products` collection: + +```js +db.products.createIndex({ name: 1 }, { unique: true }) +``` + +Unique indexes can be compound. +Here is an example of a unique index consisting +of the `category` and `name` fields from the `products` collection: + +```js +db.products.createIndex({ category: 1, name: 1 }, { unique: true }) +``` + +### Index creation details + +- If the `createIndexes()` command is called for a non-existent collection, it will create the collection and its given indexes. +- If the `createIndexes()` command is called for a non-existent field, an index for the field is created without creating or adding the field to an existing collection. +- If you attempt to create an index with the same name and key as an existing index, the system will not create a duplicate index. + Instead, it will simply return the name and key of the existing index, since duplicate indexes would be redundant and inefficient. +- Meanwhile, any attempt to call `createIndexes()` command for an existing index using the same name and different key, _or_ different name but the same key will return an error. + +## How to list indexes + +To display a collection's index details, use the `listIndexes()` command. +You can also use the `getIndexes()` method to call the `listIndexes()` command. + +To return the list of indexes in the `products` collection, use the following command: + +```js +db.products.getIndexes() +``` + +The returned indexes should look like this, showing the default index, single field index, and compound index. + +```js +{ + cursor: { + id: Long("0"), + ns: 'db.products', + firstBatch: [ + { v: 2, key: { _id: 1 }, name: '_id_' }, + { v: 2, key: { price: 1 }, name: 'price_1' }, + { + v: 2, + key: { price: 1, category: 1 }, + name: 'price_1_category_1' + } + ] + }, + ok: 1 +} +``` + +## How to drop indexes + +You can also drop all the indexes or a particular index in a specified collection, except the default index (`_id`). + +FerretDB supports the use of the `dropIndexes()` command. +You can also use the `dropIndex()` method to call the `dropIndexes()` command to a particular index from a collection. + +Using the returned indexes above, let's drop the index with the name `price_1`. + +```js +db.products.dropIndex('price_1') +``` + +Another way to perform this action is to use the same index document as the index you want to drop. +For the same example above, you can rewrite it as: + +```js +db.products.dropIndex({ price: 1 }) +``` + +Using the `dropIndexes()` command, specify the index as `"*"` to remove all indexes from the collection, except the `_id` index. + +```js +db.products.dropIndexes('*') +``` + +This will drop all the non-`_id` indexes from the collection. diff --git a/website/versioned_docs/version-v1.16/main.md b/website/versioned_docs/version-v1.16/main.md new file mode 100644 index 000000000000..c94611dc92ad --- /dev/null +++ b/website/versioned_docs/version-v1.16/main.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 1 +slug: / +description: This is the FerretDB documentation, containing all the details on FerretDB – the open-source MongoDB alternative that translates MongoDB wire protocol queries to SQL, with PostgreSQL or SQLite as the database engine. +--- + +# Introduction + +FerretDB is an open-source proxy that translates MongoDB wire protocol queries to SQL, +with PostgreSQL or SQLite as the database engine. + +Initially built as open-source software, MongoDB was a game-changer for many developers, +enabling them to build fast and robust applications. +Its ease of use and extensive documentation made it a top choice for many developers looking +for an open-source database. +However, all this changed when they switched to an SSPL license, +moving away from their open-source roots. + +In light of this, FerretDB was founded to become the true open-source alternative to MongoDB, +making it the go-to choice for most MongoDB users looking for an open-source alternative to MongoDB. +With FerretDB, users can run the same MongoDB protocol queries without needing to learn a new language or command. + +## Scope and current state + +FerretDB is compatible with MongoDB drivers and can be used as a direct replacement for MongoDB 5.0+. +We are constantly adding features to increase compatibility based on user feedback. + +See our [public roadmap](https://github.com/orgs/FerretDB/projects/2/views/1), +a list of [known differences with MongoDB](diff.md), +and [contributing guidelines](https://github.com/FerretDB/FerretDB/blob/main/CONTRIBUTING.md). + +## Community + +- Website and blog: https://www.ferretdb.com/. +- Twitter: [@ferret_db](https://twitter.com/ferret_db). +- Mastodon: [@ferretdb@techhub.social](https://techhub.social/@ferretdb). +- [Slack chat](https://join.slack.com/t/ferretdb/shared_invite/zt-zqe9hj8g-ZcMG3~5Cs5u9uuOPnZB8~A) for quick questions. +- [GitHub Discussions](https://github.com/FerretDB/FerretDB/discussions) for longer topics. +- [GitHub Issues](https://github.com/FerretDB/FerretDB/issues) for bugs and missing features. +- [Open Office Hours meeting](https://calendar.google.com/event?action=TEMPLATE&tmeid=NjNkdTkyN3VoNW5zdHRiaHZybXFtb2l1OWtfMjAyMTEyMTNUMTgwMDAwWiBjX24zN3RxdW9yZWlsOWIwMm0wNzQwMDA3MjQ0QGc&tmsrc=c_n37tquoreil9b02m0740007244%40group.calendar.google.com&scp=ALL) + every Monday at 18:00 UTC at [Google Meet](https://meet.google.com/mcb-arhw-qbq). + +If you want to contact FerretDB Inc., please use [this form](https://www.ferretdb.com/contact/). diff --git a/website/versioned_docs/version-v1.16/migration/_category_.yml b/website/versioned_docs/version-v1.16/migration/_category_.yml new file mode 100644 index 000000000000..d4668fd46751 --- /dev/null +++ b/website/versioned_docs/version-v1.16/migration/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Migrating to FerretDB +position: 9 +link: + type: generated-index + slug: /migration/ + description: > + This section details the procedures on how to migrate to FerretDB diff --git a/website/versioned_docs/version-v1.16/migration/migrating-from-mongodb.md b/website/versioned_docs/version-v1.16/migration/migrating-from-mongodb.md new file mode 100644 index 000000000000..1d95069f2311 --- /dev/null +++ b/website/versioned_docs/version-v1.16/migration/migrating-from-mongodb.md @@ -0,0 +1,66 @@ +--- +sidebar_position: 2 +--- + +# Migrating from MongoDB + +Before you begin this section of the migration process, go through the pre-migration process so as to ensure a successful migration from MongoDB to FerretDB: + +- [Pre-migration testing](premigration-testing.md) + +This guide will help you migrate your data from MongoDB – locally or online – to FerretDB. + +As an open-source MongoDB alternative, FerretDB is built to work with many MongoDB tools. +In that case, you can migrate your data using MongoDB native tools such as `mongodump`/`mongorestore` and `mongoexport`/`mongoimport`. + +Before you go forward with the migration, you need to have the following: + +- MongoDB connection URI +- FerretDB connection URI +- MongoDB native tools + +## Backup your MongoDB data + +To backup your MongoDB instance using `mongodump` or `mongoexport`, you'll need to set the connection string to your MongoDB instance (e.g. `"mongodb://127.0.0.1:27017"`) to run the following command: + +```sh +mongodump --uri="mongodb://:@:" +``` + +The `mongodump` command will create a dump of all the data in the instance, consisting of BSON files of all the collections. +Also, you can migrate a specific database (e.g. `--db=test`) or collection (e.g. `--collection=supply`) using their respective parameters after the `--uri` connection string. + +:::caution +If you include the database in your connection string, there's no need to specify a database name for the backup or restore process. +::: + +```sh +mongoexport --uri="mongodb://:@:" --db= --collection= --out=.json +``` + +On the other hand, `mongoexport` does not provide a direct way to export all the collections at once, like `mongodump` does. + +Instead, you need to set the connection string to connect with your preferred database and then run the command together with the parameters for the collection (`--collection=myCollection`) and the directory you want to export to (e.g. `--out=collection-name.json`). + +## Restore your data to FerretDB + +To restore or import your backed-up data to FerretDB, set the connection string to your FerretDB instance and use `mongorestore` and `mongoimport`. + +Run the following command in your terminal, from your `dump` folder: + +```sh +mongorestore --uri="mongodb://:@:/?authMechanism=PLAIN" +``` + +With this command, you can restore all the data in `dump` into your FerretDB instance. +You can also specify the database and collection (`dump//`) you want to restore from the `dump` folder, according to your preferences. + +To import your database using `mongoimport`, run the command from the terminal directory where you exported your data: + +````sh + +```sh +mongoimport--uri="mongodb://:@:/?authMechanism=PLAIN" --db= --collection= --file=.json +```` + +The command will import the specified collection you exported from your MongoDB instance to FerretDB. diff --git a/website/versioned_docs/version-v1.16/migration/premigration-testing.md b/website/versioned_docs/version-v1.16/migration/premigration-testing.md new file mode 100644 index 000000000000..fce33ba77e90 --- /dev/null +++ b/website/versioned_docs/version-v1.16/migration/premigration-testing.md @@ -0,0 +1,233 @@ +--- +sidebar_position: 1 +--- + +# Pre-migration testing + +To ensure a smooth and successful migration from MongoDB, we offer several methods through which you can test your application with FerretDB. + +## Operation modes + +We offer multiple operation modes which help facilitate the testing of your application by enabling FerretDB to act as a proxy. +For more details, refer to the [operation modes](../configuration/operation-modes.md). + +### Manual and automated testing with `diff-normal` mode + +For details on how to install FerretDB, refer to the [quickstart guide](../../quickstart-guide/). + +You can manually test your application or use integration tests, among other methods. +Afterward, you can inspect the differential output for errors or inconsistencies between responses that require your attention. + +As an example, let us say that your application performs some complex query and you'd like to test it in `diff-normal` mode. +You would do the following: + +1. Start FerretDB in `diff-normal` mode. + + This can be achieved by setting the `--mode` [flag](../configuration/flags.md) or `FERRETDB_MODE` environment variable to `diff-normal`. + By default, FerretDB starts in normal mode (`--mode=normal`/`FERRETDB_MODE=normal`). + For more details, see [operation modes](../configuration/operation-modes.md). + + Ensure to specify `--listen-addr` and `--proxy-addr` flags or set the `FERRETDB_LISTEN_ADDR` and `FERRETDB_PROXY_ADDR` environment variables. + Specify the address of your MongoDB instance for `--proxy-addr` flag or `FERRETDB_PROXY_ADDR` environment variable. + [See docs for more details](https://docs.ferretdb.io/configuration/flags/#interfaces). For example: + + ```sh + ferretdb --mode=diff-normal \ + --proxy-addr= \ + --listen-addr= \ + --postgresql-url= + ``` + + The `--listen-addr` flag or the `FERRERDB_LISTEN_ADDR` environment variable is set to `127.0.0.1:27017` by default. + +2. Run `mongosh` to connect to the `--listen-addr` and then insert some documents. +3. Run a query to fetch the first post from each author sorted by date and author. + + Please note that due to running in `diff-normal` mode, any error returned from FerretDB will be transmitted to the client, allowing us to promptly identify the issue. + In the majority of cases, this does not necessitate additional scrutiny of the diff output. + Nevertheless, if FerretDB does not handle the error, additional inspection becomes necessary. + + ```sh + # run mongosh + $ mongosh + ``` + + ```js + // insert some documents + db.posts.insertMany([ + { + title: 'title A', + body: 'some content', + author: 'Bob', + date: ISODate('2023-08-29T10:33:23.134Z') + }, + { + title: 'another title', + body: 'some content', + author: 'Bob', + date: ISODate('2023-08-28T10:33:23.134Z') + }, + { + title: 'title B', + body: 'some content', + author: 'Alice', + date: ISODate('2023-08-20T10:33:23.134Z') + }, + { + title: 'some other title', + body: 'some content', + author: 'Alice', + date: ISODate('2023-08-21T10:33:23.134Z') + } + ]) + + // run the query + db.posts.aggregate([ + { $sort: { date: 1, author: 1 } }, + { + $group: { + _id: '$author', + firstPost: { $first: '$date' } + } + } + ]) + // the below error is returned to the client: + // MongoServerError: $group accumulator "$first" is not implemented yet + ``` + +### Manual and automated testing with `diff-proxy` mode + +Continuing with the same example above, we can further examine the diff output while in `diff-proxy` mode. + +1. Run FerretDB in `diff-proxy` mode. + This can again be achieved by using the `--mode` [flag](../configuration/flags.md) or by setting the `FERRETDB_MODE` environment variable to `diff-proxy`. +2. Follow the same instructions as the one for `diff-normal` above to run FerretDB in `diff-proxy` mode and re-run the query. + + ```js + db.posts.aggregate([ + { $sort: { date: 1, author: 1 } }, + { + $group: { + _id: '$author', + firstPost: { $first: '$date' } + } + } + ]) + // the query was handled by MongoDB, so the following documents are returned: + // { _id: 'Alice', firstPost: ISODate("2023-08-20T10:33:23.134Z") } + // { _id: 'Bob', firstPost: ISODate("2023-08-28T10:33:23.134Z") } + ``` + +In the diff output below, however, we have discovered that the query cannot be serviced by our application because the `$first` accumulator operator is not implemented in FerretDB. + +```diff +2023-08-29T13:25:09.048+0200 WARN // 127.0.0.1:33522 -> 127.0.0.1:27017 clientconn/conn.go:360 Header diff: +--- res header ++++ proxy header +@@ -1 +1 @@ +-length: 140, id: 2, response_to: 156, opcode: OP_MSG ++length: 181, id: 360, response_to: 156, opcode: OP_MSG + +Body diff: +--- res body ++++ proxy body +@@ -7,13 +7,41 @@ + "$k": [ +- "ok", +- "errmsg", +- "code", +- "codeName" ++ "cursor", ++ "ok" + ], ++ "cursor": { ++ "$k": [ ++ "firstBatch", ++ "id", ++ "ns" ++ ], ++ "firstBatch": [ ++ { ++ "$k": [ ++ "_id", ++ "firstPost" ++ ], ++ "_id": "Alice", ++ "firstPost": { ++ "$d": 1692527603134 ++ } ++ }, ++ { ++ "$k": [ ++ "_id", ++ "firstPost" ++ ], ++ "_id": "Bob", ++ "firstPost": { ++ "$d": 1693218803134 ++ } ++ } ++ ], ++ "id": { ++ "$l": "0" ++ }, ++ "ns": "test.posts" ++ }, + "ok": { +- "$f": 0 +- }, +- "errmsg": "$group accumulator \"$first\" is not implemented yet", +- "code": 238, +- "codeName": "NotImplemented" ++ "$f": 1 ++ } + }, +``` + +### Response metrics + +Metrics are captured and written to standard output (`stdout`) upon exiting in [Debug builds](https://pkg.go.dev/github.com/FerretDB/FerretDB/build/version#hdr-Debug_builds). +This is a useful way to quickly determine what commands are not implemented for the client requests sent by your application. +In the metrics provided below, we can observe that the `$first` accumulator operator was invoked 18 times within the aggregate command, and the `findAndModify` command was executed 6 times with a `fields` projection document. +Both of these operations resulted in `result="NotImplemented"`. +To address this issue, it's essential to carefully inspect any result that lacks an `ok` value. + +```text +# HELP ferretdb_client_requests_total Total number of requests. +# TYPE ferretdb_client_requests_total counter +ferretdb_client_requests_total{command="aggregate",opcode="OP_MSG"} 105 +ferretdb_client_requests_total{command="find",opcode="OP_MSG"} 398 +ferretdb_client_requests_total{command="findAndModify",opcode="OP_MSG"} 6 +ferretdb_client_requests_total{command="hello",opcode="OP_MSG"} 4 +ferretdb_client_requests_total{command="insert",opcode="OP_MSG"} 10 +ferretdb_client_requests_total{command="ismaster",opcode="OP_MSG"} 17 +ferretdb_client_requests_total{command="unknown",opcode="OP_QUERY"} 28 +ferretdb_client_requests_total{command="update",opcode="OP_MSG"} 59 +# HELP ferretdb_client_responses_total Total number of responses. +# TYPE ferretdb_client_responses_total counter +ferretdb_client_responses_total{argument="$first (accumulator)",command="aggregate",opcode="OP_MSG",result="NotImplemented"} 18 +ferretdb_client_responses_total{argument="fields",command="findAndModify",opcode="OP_MSG",result="NotImplemented"} 6 +ferretdb_client_responses_total{argument="unknown",command="aggregate",opcode="OP_MSG",result="ok"} 87 +ferretdb_client_responses_total{argument="unknown",command="find",opcode="OP_MSG",result="ok"} 398 +ferretdb_client_responses_total{argument="unknown",command="hello",opcode="OP_MSG",result="ok"} 4 +ferretdb_client_responses_total{argument="unknown",command="insert",opcode="OP_MSG",result="ok"} 10 +ferretdb_client_responses_total{argument="unknown",command="ismaster",opcode="OP_MSG",result="ok"} 17 +ferretdb_client_responses_total{argument="unknown",command="unknown",opcode="OP_REPLY",result="ok"} 28 +ferretdb_client_responses_total{argument="unknown",command="update",opcode="OP_MSG",result="ok"} 59 +``` + +### Other tools + +We also have a fork of the Amazon DocumentDB Compatibility Tool [here](https://github.com/FerretDB/amazon-documentdb-tools/tree/master/compat-tool). +The tool examines files to identify queries that use unsupported operators in FerretDB. +Please note that this tool is not highly accurate and may generate inaccurate reports, as it does not parse query syntax with contextual information about the originating command. +For example, an unsupported operator might appear within a `find` or `aggregate` command, which the tool does not differentiate. +Note that we also mark operators as unsupported if they are not supported in _all_ commands, which could result in false negatives. + +Running the tool to check FerretDB compatibility: + +```sh +# clone the repository and run the compat-tool +$ git clone https://github.com/FerretDB/amazon-documentdb-tools.git && cd amazon-documentdb-tools/compat-tool +$ python3 compat.py --directory=/path/to/myapp --version=FerretDB +``` diff --git a/website/versioned_docs/version-v1.16/operators/_category_.yml b/website/versioned_docs/version-v1.16/operators/_category_.yml new file mode 100644 index 000000000000..5dd8c8338976 --- /dev/null +++ b/website/versioned_docs/version-v1.16/operators/_category_.yml @@ -0,0 +1,9 @@ +--- +label: Operators +position: 5 +link: + type: generated-index + slug: /operators/ + description: > + The complete list of operators, including query operators, update operators, + aggregation operators, etc. diff --git a/website/versioned_docs/version-v1.16/operators/query/_category_.yml b/website/versioned_docs/version-v1.16/operators/query/_category_.yml new file mode 100644 index 000000000000..75be6a917b7a --- /dev/null +++ b/website/versioned_docs/version-v1.16/operators/query/_category_.yml @@ -0,0 +1,9 @@ +--- +label: Query Operators +position: 1 +link: + type: generated-index + slug: /query/ + description: > + The list of all different types of query operators available on FerretDB, + including comparison operators, logical operators, array operators, etc. diff --git a/website/versioned_docs/version-v1.16/operators/query/array-operators.md b/website/versioned_docs/version-v1.16/operators/query/array-operators.md new file mode 100644 index 000000000000..e4943f0e00a3 --- /dev/null +++ b/website/versioned_docs/version-v1.16/operators/query/array-operators.md @@ -0,0 +1,195 @@ +--- +sidebar_position: 3 +--- + +# Array query operators + +Array query operators allow you to search for specific elements within an array field in a document. + +| Operator | Description | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| [`$all`](#all) | Selects an array that contains all elements from a given query. | +| [`$elemMatch`](#elemmatch) | Matches a document that contains an array field with at least one element that matches all the specified query criteria | +| [`$size`](#size) | Matches an array with a specified number of elements | + +For the examples in this section, insert the following documents into the `team` collection: + +```js +db.team.insertMany([ + { + id: 1, + name: 'Jack Smith', + position: 'Manager', + skills: ['leadership', 'communication', 'project management'], + contact: { + email: 'john@example.com', + phone: '123-456-7890' + }, + active: true + }, + { + id: 2, + name: 'Jane Mark', + position: 'Software Developer', + skills: ['Java', 'Python', 'C++'], + contact: { + email: 'jane@example.com', + phone: '123-456-7891' + }, + active: false + }, + { + id: 3, + name: 'Bob Johnson', + position: 'Graphic Designer', + skills: ['Adobe Photoshop', 'Illustrator', 'InDesign'], + contact: { + email: 'bob@example.com', + phone: '123-456-7892' + }, + active: true + }, + { + id: 4, + name: 'Alice Williams', + position: 'Marketing Coordinator', + skills: ['communication', 'content creation', 'event planning'], + contact: { + email: 'alice@example.com', + phone: '123-456-7893' + }, + active: true + } +]) +``` + +## $all + +_Syntax_: `{ : { $all: [ , , ... ] } }` + +Use the `$all` operator when you want to select documents that contain every single element in a specified array. + +:::note +When using an `$all` operator, the order of the elements and array size does not matter, as long as the array contains all the elements in the query. +::: + +**Example:** Find all documents in the `team` collection where the `skills` field contains both `communication` and `content creation` as elements using the following query operation: + +```js +db.team.find({ + skills: { + $all: ['communication', 'content creation'] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a5bb4acf72d6203bb45bb5"), + id: 4, + name: 'Alice Williams', + position: 'Marketing Coordinator', + skills: ['communication', 'content creation', 'event planning'], + contact: { email: 'alice@example.com', phone: '123-456-7893' }, + active: true + } +] +``` + +## $elemMatch + +_Syntax_: `{ : { $elemMatch: { , , ... } } }` + +To select documents in a specified array field where one or more elements match all listed query conditions, use the `$elemMatch` operator. + +**Example:** Find documents in the `team` collection where the `skills` field is an array that contains the element "Java", and array does not contain the element `communication`. +Use the following query operation: + +```js +db.team.find({ + skills: { + $elemMatch: { + $eq: 'Java', + $nin: ['communication'] + } + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63aa247e69c82de72bd40b93"), + id: 2, + name: 'Jane Mark', + position: 'Software Developer', + skills: ['Java', 'Python', 'C++'], + contact: { email: 'jane@example.com', phone: '123-456-7891' }, + active: false + } +] +``` + +## $size + +_Syntax_: `{ : { $size: } }` + +The `$size` operator is ideal for selecting array fields containing a specified number of elements. + +**Example:** Select the documents in the `team` collection where the `skills` array contains only three elements. + +```js +db.team.find({ + skills: { + $size: 3 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63aa247e69c82de72bd40b92"), + id: 1, + name: 'Jack Smith', + position: 'Manager', + skills: ['leadership', 'communication', 'project management'], + contact: { email: 'john@example.com', phone: '123-456-7890' }, + active: true + }, + { + _id: ObjectId("63aa247e69c82de72bd40b93"), + id: 2, + name: 'Jane Mark', + position: 'Software Developer', + skills: ['Java', 'Python', 'C++'], + contact: { email: 'jane@example.com', phone: '123-456-7891' }, + active: false + }, + { + _id: ObjectId("63aa247e69c82de72bd40b94"), + id: 3, + name: 'Bob Johnson', + position: 'Graphic Designer', + skills: ['Adobe Photoshop', 'Illustrator', 'InDesign'], + contact: { email: 'bob@example.com', phone: '123-456-7892' }, + active: true + }, + { + _id: ObjectId("63aa247e69c82de72bd40b95"), + id: 4, + name: 'Alice Williams', + position: 'Marketing Coordinator', + skills: ['communication', 'content creation', 'event planning'], + contact: { email: 'alice@example.com', phone: '123-456-7893' }, + active: true + } +] +``` diff --git a/website/versioned_docs/version-v1.16/operators/query/bitwise-operators.md b/website/versioned_docs/version-v1.16/operators/query/bitwise-operators.md new file mode 100644 index 000000000000..14a01d1756f5 --- /dev/null +++ b/website/versioned_docs/version-v1.16/operators/query/bitwise-operators.md @@ -0,0 +1,159 @@ +--- +sidebar_position: 1 +--- + +# Bitwise query operators + +Bitwise query operators help to select documents by evaluating query conditions according to the location of bits. + +| Operator | Description | +| -------------------------------- | ---------------------------------------------------------- | +| [`$bitsAllClear`](#bitsallclear) | Selects documents with clear bit locations (0) | +| [`$bitsAllSet`](#bitsallset) | Selects documents with set bit locations (1) | +| [`$bitsAnyClear`](#bitsanyclear) | Selects documents with at least one clear bit location (0) | +| [`$bitsAnySet`](#bitsanyset) | Selects documents with at least one set bit location (1) | + +For the examples in this section, insert the following documents into the `numbers` collection: + +```js +db.numbers.insertMany([ + { _id: 1, value: 23, binaryValue: '10111' }, + { _id: 2, value: 56, binaryValue: '111000' }, + { _id: 3, value: 67, binaryValue: '1000011' }, + { _id: 4, value: 102, binaryValue: '1100110' }, + { _id: 5, value: 5, binaryValue: '101' } +]) +``` + +## $bitsAllClear + +_Syntax_: `{ : { $bitsAllClear: } }` + +Use the `$bitsAllClear` operator to select documents where the specified bitmask locations in the query are clear (0). + +:::tip +The bitmask can either be a numeric or BinData value. +A BinData value is a BSON type that represents a binary value. +The position of the bits is read from right to left with the rightmost position being `0`. +::: + +**Example:** The following query returns documents in which the `value` field has the second and third bit (position `1` and position `2`) from the right as clear (0). + +```js +db.numbers.find({ + value: { + $bitsAllClear: 6 + } +}) +``` + +The binary representation for `6` in this query is `110`. +The query can also be written to show the positions of the bits to be checked: + +```js +db.numbers.find({ + value: { + $bitsAllClear: [1, 2] + } +}) +``` + +The output: + +```json5 +[{ _id: 2, value: 56, binaryValue: '111000' }] +``` + +For the same query above, the bitmask can also be written as a BinData value: + +```js +db.numbers.find({ + value: { + $bitsAllClear: BinData(0, 'Bg==') + } +}) +``` + +## $bitsAllSet + +_Syntax_: `{ : { $bitsAllSet: } }` + +To select documents where the bitmask locations in a query are set (1), use the `$bitsAllSet` operator. + +**Example:** The following query returns all the documents with positions `1` and positions `2` as set (1): + +```js +db.numbers.find({ + value: { + $bitsAllSet: [1, 2] + } +}) +``` + +The output: + +```json5 +[ + { _id: 1, value: 23, binaryValue: '10111' }, + { _id: 4, value: 102, binaryValue: '1100110' } +] +``` + +See the [$bitsAllClear query operator](#bitsallclear) section for more usage examples. + +## $bitsAnyClear + +_Syntax_: `{ : { $bitsAnyClear: } }` + +Use the `$bitsAnyClear` operator to select documents where at least one of the bitmask locations in the query is clear (0). + +**Example:** The following query returns all the documents with positions `0` and positions `2` as clear (0): + +```js +db.numbers.find({ + value: { + $bitsAnyClear: [0, 2] + } +}) +``` + +The output: + +```json5 +[ + { _id: 2, value: 56, binaryValue: '111000' }, + { _id: 3, value: 67, binaryValue: '1000011' }, + { _id: 4, value: 102, binaryValue: '1100110' } +] +``` + +See the [$bitsAllClear query operator](#bitsallclear) section for more usage examples. + +## $bitsAnySet + +_Syntax_: `{ : { $bitsAnySet: } }` + +The `$bitsAnySet` operator selects documents where at least one of the bitmask locations in the query is set (1). + +**Example:** The following query returns all the documents with positions `0` and positions `2` as set (1): + +```js +db.numbers.find({ + value: { + $bitsAnySet: [0, 2] + } +}) +``` + +The output: + +```json5 +[ + { _id: 1, value: 23, binaryValue: '10111' }, + { _id: 3, value: 67, binaryValue: '1000011' }, + { _id: 4, value: 102, binaryValue: '1100110' }, + { _id: 5, value: 5, binaryValue: '101' } +] +``` + +See the [$bitsAllClear query operator](#bitsallclear) section for more usage examples. diff --git a/website/versioned_docs/version-v1.16/operators/query/comparison-operators.md b/website/versioned_docs/version-v1.16/operators/query/comparison-operators.md new file mode 100644 index 000000000000..e4033deffece --- /dev/null +++ b/website/versioned_docs/version-v1.16/operators/query/comparison-operators.md @@ -0,0 +1,383 @@ +--- +sidebar_position: 1 +--- + +# Comparison query operators + +Comparison query operators allow you to compare the elements in a document to a given query value. + +Go to the comparison query operators: + +| Operator | Description | +| -------------- | ------------------------------------------------------------------------- | +| [`$eq`](#eq) | Selects documents with elements that are equal to a given query value | +| [`$gt`](#gt) | Selects documents with elements that are greater than a given query value | +| [`$gte`](#gte) | Selects documents greater than or equal to specified query | +| [`$lt`](#lt) | Selects documents with elements that are less than a given query value | +| [`$lte`](#lte) | Selects documents with elements less than or equal to given query value | +| [`$in`](#in) | Selects documents that contain the elements in a given array query | +| [`$ne`](#ne) | Selects documents with elements that are not equal to given query value | +| [`$nin`](#nin) | Selects documents that do not contain the elements in a given array query | + +For the examples in this section, insert the following documents into the `employees` collection: + +```js +db.employees.insertMany([ + { + name: { + first: 'Earl', + last: 'Thomas' + }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + name: { + first: 'Sam', + last: 'Johnson' + }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + name: { + first: 'Clarke', + last: 'Dane' + }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +]) +``` + +## $eq + +_Syntax_: `{ : { $eq: } }` + +To select documents that exactly match a given query value, use the `$eq` operator. + +This operator can be used to match values of different types, including documents, array, embedded documents, etc. + +**Example:** The following operation queries the `employees` collection for all documents where the field `age` equals `21`. + +```js +db.employees.find({ + age: { + $eq: 21 + } +}) +``` + +The response returns a single document that matches the query: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +**Example:** To query values in an embedded document, use [dot notation](../../understanding-ferretdb.md#dot-notation). +The following operation queries the `employees` collection for documents that match the field `first` in the embedded document `name`. + +```js +db.employees.find({ + 'name.first': { + $eq: 'Earl' + } +}) +``` + +The response returns a single document that matches the query: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + } +] +``` + +## $gt + +_Syntax_: `{ : { $gt: } }` + +To identify documents containing elements that have a greater value than the specified one in the query, use the `$gt` operator. + +**Example:** Use the following operation to query for all the documents in the `employees` collection where the field `age` is greater than `21`. + +```js +db.employees.find({ + age: { + $gt: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + } +] +``` + +## $gte + +_Syntax_: `{ : { $gte: } }` + +Use the `$gte` to select document with elements that are greater than or equal to a specified value. + +**Example:** The following operation selects documents based on the specified query, where the field `age` is greater than or equal to `21`. + +```js +db.employees.find({ + age: { + $gte: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $lt + +_Syntax_: `{ : { $lt: } }` + +Contrary to the `$gt` operator, the `$lt` operator is ideal for selecting documents with elements that are of a lesser value than that of the specified query. + +**Example:** The following operation queries for documents where the field `age` is less than `25`. + +```js +db.employees.find({ + age: { + $lt: 25 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $lte + +_Syntax_: `{ : { $lte: } }` + +The `$lte` operator is the opposite of the `$gte` operator. +Use the `$lte` operator to select documents with elements that are less than or equal to the specified query value. + +**Example:** The following operation queries for documents where the field `age` is less than or equal to `21`. + +```js +db.employees.find({ + age: { + $lte: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $in + +_Syntax_: `{ : { $in: [, , ... ] } }` + +To select documents containing any of the listed elements in a specified array field, use the `$in` operator. + +**Example:** The following operation queries the `employees` collection for documents where the value of the field `age` is either `21` or `35`. + +```js +db.employees.find({ + age: { + $in: [21, 35] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0e"), + name: { first: 'Clarke', last: 'Dane' }, + employeeID: 3234, + age: 21, + role: 'salesperson', + catalog: ['printer', 'pencils', 'crayons', 'toys'] + } +] +``` + +## $ne + +_Syntax_: `{ : { $ne: } }` + +Use the `$ne` operator to select all the documents with elements that are not equal to a given query. + +**Example:** The following operation queries the `employees` collection for documents where the field `age` is not equal to `21`. + +```js +db.employees.find({ + age: { + $ne: 21 + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + }, + { + _id: ObjectId("639a3cce071b6bed396a8f0d"), + name: { first: 'Sam', last: 'Johnson' }, + employeeID: 2234, + age: 35, + role: 'salesperson', + catalog: ['cabinet', 'fridge', 'blender', 'utensils'] + } +] +``` + +## $nin + +_Syntax_: `{ : { $nin: [ , ... ] } }` + +The `$nin` does exactly the opposite of the `$in` operator. +Use the `$nin` operator when selecting documents that do match or contain any of the elements listed in an array query. + +**Example:** The following operation queries the `employees` collection for documents where the value of the field `age` is not `21` or `35`. + +```js +db.employees.find({ + age: { + $nin: [21, 35] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639a3cce071b6bed396a8f0c"), + name: { first: 'Earl', last: 'Thomas' }, + employeeID: 1234, + age: 23, + role: 'salesperson', + catalog: ['printer', 'cardboard', 'crayons', 'books'] + } +] +``` diff --git a/website/versioned_docs/version-v1.16/operators/query/element-operators.md b/website/versioned_docs/version-v1.16/operators/query/element-operators.md new file mode 100644 index 000000000000..c18d1f105a15 --- /dev/null +++ b/website/versioned_docs/version-v1.16/operators/query/element-operators.md @@ -0,0 +1,363 @@ +--- +sidebar_position: 4 +--- + +# Element query operators + +Element query operators return data based on the existence of a specified field or the data type of a particular value. + +| Operator | Description | +| -------------------- | ------------------------------------------------------------ | +| [`$exists`](#exists) | returns documents where a field exists or does not exist | +| [`$type`](#type) | matches document containing elements with the specified type | + +For the examples in this section, insert the following documents into the `electronics` collection: + +```js +db.electronics.insertMany([ + { + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [ + { + processor: 'Intel Core i7' + }, + { + memory: 16 + } + ] + }, + { + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [ + { + brand: 'Apple' + }, + { + model: 'iPhone 12' + } + ] + }, + { + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [ + { + brand: 'Samsung' + }, + { + model: 'Galaxy Tab S7' + } + ] + }, + { + product: 'keyboard', + price: 100, + stock: 20 + }, + { + product: 'mouse', + price: 50, + stock: 25, + discount: null, + specifications: [] + }, + { + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [ + { + size: 27 + }, + { + resolution: '4K' + } + ] + }, + { + product: 'printer', + price: 150, + stock: 35, + discount: false + }, + { + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [ + { + type: 'flatbed' + } + ] + } +]) +``` + +## $exists + +_Syntax_: `{ : { $exists: } }` + +To find out if a particular field exists in a document, use the `$exists` operator. + +:::tip +If the `` value is `true`, the query returns documents where the specified field exists, even if the value is `null` or an empty array. +If the `` value is `false`, the query returns documents where the specified field does not exist. +::: + +**Example:** Find documents in the `electronics` collection where the `specifications` field exists using the `$exists` operator: + +```js +db.electronics.find({ + specifications: { + $exists: true + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a32fc7cf72d6203bb45b8e"), + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [{ processor: 'Intel Core i7' }, { memory: 16 }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b8f"), + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [{ brand: 'Apple' }, { model: 'iPhone 12' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b90"), + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [{ brand: 'Samsung' }, { model: 'Galaxy Tab S7' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b92"), + product: 'mouse', + price: 50, + stock: 25, + discount: null, + specifications: [] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b93"), + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [{ size: 27 }, { resolution: '4K' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b95"), + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [{ type: 'flatbed' }] + } +] +``` + +In the above output, the query returns all documents where the `specifications` field exists, even when the `field` has an empty value. + +If you want to find documents where the `specifications` field exists and has a specific value, use the `$exists` operator in conjunction with other operators. + +**Example:** The following query returns all documents where the `specifications` field exists and its value is an array: + +```js +db.electronics.find({ + specifications: { + $exists: true, + $type: 'array' + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a32fc7cf72d6203bb45b8e"), + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [{ processor: 'Intel Core i7' }, { memory: 16 }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b8f"), + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [{ brand: 'Apple' }, { model: 'iPhone 12' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b90"), + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [{ brand: 'Samsung' }, { model: 'Galaxy Tab S7' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b92"), + product: 'mouse', + price: 50, + stock: 25, + discount: null, + specifications: [] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b93"), + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [{ size: 27 }, { resolution: '4K' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b95"), + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [{ type: 'flatbed' }] + } +] +``` + +## $type + +_Syntax_: `{ : { $type: } }` + +Use the `$type` operator to select documents where the data type of a field matches the specified BSON type + +The `` parameter can be the type code or alias of the particular data type. + +The following table lists the available BSON type codes and their corresponding aliases: + +| Type code | Type | Alias | +| --------- | ------------------ | --------- | +| 1 | Double | double | +| 2 | String | string | +| 3 | Object | object | +| 4 | Array | array | +| 5 | Binary data | binData | +| 7 | ObjectId | objectId | +| 8 | Boolean | bool | +| 9 | Date | date | +| 10 | Null | null | +| 11 | Regular expression | regex | +| 16 | 32-bit integer | int | +| 17 | Timestamp | timestamp | +| 18 | 64-bit integer | long | +| 19 | Decimal128 | decimal | +| -1 | Min key | minKey | +| 127 | Max key | maxKey | +| -128 | Number | number | + +:::caution +`Decimal128`, `Min Key`, and `Max Key` are not currently implemented. +FerretDB supports the alias `number` which matches the following BSON types: `Double`, `32-bit integer`, and `64-bit integer` type values. +::: + +:::info +FerretDB supports the alias `number` which matches the following BSON types: `Double`, `32-bit integer`, and `64-bit integer` type values. +::: + +**Example:** The following operation query returns all documents in the `electronics` collection where the `discount` field has a boolean data type, which can be represented with the data code `8`: + +```js +db.electronics.find({ + discount: { + $type: 8 + } +}) +``` + +This query can also be written using the alias of the specified data type. + +```js +db.electronics.find({ + discount: { + $type: 'bool' + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63a32fc7cf72d6203bb45b8e"), + product: 'laptop', + price: 1500, + stock: 5, + discount: true, + specifications: [{ processor: 'Intel Core i7' }, { memory: 16 }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b8f"), + product: 'phone', + price: 800, + stock: 10, + discount: true, + specifications: [{ brand: 'Apple' }, { model: 'iPhone 12' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b90"), + product: 'tablet', + price: 500, + stock: 15, + discount: true, + specifications: [{ brand: 'Samsung' }, { model: 'Galaxy Tab S7' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b93"), + product: 'monitor', + price: 250, + stock: 30, + discount: true, + specifications: [{ size: 27 }, { resolution: '4K' }] + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b94"), + product: 'printer', + price: 150, + stock: 35, + discount: false + }, + { + _id: ObjectId("63a32fc7cf72d6203bb45b95"), + product: 'scanner', + price: 100, + stock: 40, + discount: true, + specifications: [{ type: 'flatbed' }] + } +] +``` diff --git a/website/versioned_docs/version-v1.16/operators/query/evaluation-operators.md b/website/versioned_docs/version-v1.16/operators/query/evaluation-operators.md new file mode 100644 index 000000000000..3a6b046ecaf0 --- /dev/null +++ b/website/versioned_docs/version-v1.16/operators/query/evaluation-operators.md @@ -0,0 +1,164 @@ +--- +sidebar_position: 5 +--- + +# Evaluation query operators + +Evaluation query operators return data based on the evaluation of a specified expression. + +| Operator | Description | +| ------------------ | ----------------------------------------------------------------------------------------------------------------- | +| [`$mod`](#mod) | Matches documents where the field element is divided by a given value and returns a the specified remainder value | +| [`$regex`](#regex) | Matches documents where a field matches a specified regular expression query | + +For the examples in this section, insert the following documents into the `catalog` collection: + +```js +db.catalog.insertMany([ + { + product: 'bottle', + price: 15, + stock: 1 + }, + { + product: 'spoon', + price: 500, + stock: 0 + }, + { + product: 'cup', + price: 100, + stock: 14 + }, + { + product: 'BoWL', + price: 56, + stock: 5 + }, + { + product: 'boTtLe', + price: 20, + stock: 3 + } +]) +``` + +## $mod + +_Syntax_: `{ : { $mod: [ , ] } }` + +The `$mod` operator matches documents where the field element divided by a given value returns a specified remainder (otherwise known as a modulus). +The mathematical operation for this is `field-value % divisor-value = modulus`. + +**Example:** The following query returns all the documents where the value of the "stock" field is evenly divisible by 2: + +```js +db.catalog.find({ + stock: { + $mod: [2, 0] + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63e3ac0184f488929a3f737a"), + product: 'spoon', + price: 500, + stock: 0 + }, + { + _id: ObjectId("63e3ac0184f488929a3f737b"), + product: 'cup', + price: 100, + stock: 14 + } +] +``` + +:::caution +Note that the `$mod` expression returns an error if you only have a single element in the array, more than two elements in the array, or if the array is empty. +It also rounds down decimal input down to zero (e.g. `$mod: [ 3.5 , 2 ]` is executed as `$mod: [ 3 , 2 ]`). +::: + +## $regex + +_Syntax_: `{ : { $regex: '', $options: '' } }` + +Other syntaxes: `{ : { $regex: //, $options: '' } }` and `{ : // }`. + +To use regular expression for queries on particular fields, use the `$regex` operator. + +**Example:** The following query returns all the documents where the value of the "product" field starts with the letter "b": + +```js +db.catalog.find({ + product: { + $regex: /^b/ + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63e4ce469695494b86bf2b2d"), + product: 'bottle', + price: 15, + stock: 1 + }, + { + _id: ObjectId("63e4ce469695494b86bf2b31"), + product: 'boTtLe', + price: 20, + stock: 3 + } +] +``` + +`$options` is an optional parameter that specifies the regular expression flags to use, such as: + +- Case-insensitivity (`i`) +- Multi-line matching (`m`) +- Dot character matching (`s`) + +:::note +The regex flag for ignoring white spaces (`x`) is not currently supported. +Follow [here](https://github.com/FerretDB/FerretDB/issues/592) for more updates. +::: + +To perform case-insensitive matching, use the `i` flag in the `regex` expression. + +**Example:** The following query returns all the documents where the value of the "product" field is equal to "bottle" (case-insensitive): + +```js +db.catalog.find({ + product: { + $regex: /bottle/i + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("63e3ac0184f488929a3f7379"), + product: 'bottle', + price: 15, + stock: 1 + }, + { + _id: ObjectId("63e3ac0184f488929a3f737d"), + product: 'boTtLe', + price: 20, + stock: 3 + } +] +``` diff --git a/website/versioned_docs/version-v1.16/operators/query/logical-operators.md b/website/versioned_docs/version-v1.16/operators/query/logical-operators.md new file mode 100644 index 000000000000..aec278a1fb05 --- /dev/null +++ b/website/versioned_docs/version-v1.16/operators/query/logical-operators.md @@ -0,0 +1,309 @@ +--- +sidebar_position: 2 +--- + +# Logical query operators + +Logical query operators return data based on specified query expressions that are either true or false. + +| Operator | Description | +| -------------- | -------------------------------------------------------------------- | +| [`$and`](#and) | Joins all query expressions with a logical AND operator | +| [`$or`](#or) | Joins all query expressions with a logical OR operator | +| [`$not`](#not) | Returns all documents that do NOT match a query expression | +| [`$nor`](#nor) | Returns all documents that do not match any of the query expressions | + +For the examples in this section, insert the following documents into the `catalog` collection: + +```js +db.catalog.insertMany([ + { + product: 'bottle', + price: 15, + stock: 1, + discount: true, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['black', 'silver'] + } + ] + }, + { + product: 'spoon', + price: 500, + stock: 0, + discount: true, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['silver', 'white'] + } + ] + }, + { + product: 'cup', + price: 100, + stock: 14, + discount: true, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['red', 'black', 'white'] + } + ] + }, + { + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { + size: ['small', 'medium', 'large'] + }, + { + color: ['pink', 'white', 'red'] + } + ] + } +]) +``` + +## $and + +_Syntax_: `{ $and: [ { }, { } , ... , { } ] }` + +To satisfy more than one query condition when selecting documents, use the `$and` operator. + +**Example:** Select documents that satisfy both of these expressions in the `catalog` collection: + +- `price` field is less than `100` **AND** +- `stock` field is not `0` + +```js +db.catalog.find({ + $and: [ + { + price: { + $lt: 100 + } + }, + { + stock: { + $ne: 0 + } + } + ] +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f13"), + product: 'bottle', + price: 15, + stock: 1, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['black', 'silver'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f16"), + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['pink', 'white', 'red'] } + ] + } +] +``` + +## $or + +_Syntax_: `{ $or: [ { }, { } , ... , { } ] }` + +To satisfy either one or more conditions in a query, use the `$or` operator to join the conditions. + +**Example:** Select the documents that match these expressions: + +- `discount` field is `true` _and_ `stock` field is not `0` **OR** +- `price` field is less than or equal to `60` + +```js +db.catalog.find({ + $or: [ + { + $and: [ + { + discount: true + }, + { + stock: { + $ne: 0 + } + } + ] + }, + { + price: { + $lte: 60 + } + } + ] +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f13"), + product: 'bottle', + price: 15, + stock: 1, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['black', 'silver'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f15"), + product: 'cup', + price: 100, + stock: 14, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['red', 'black', 'white'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f16"), + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['pink', 'white', 'red'] } + ] + } +] +``` + +## $not + +_Syntax_: `{ : { $not: { } } }` + +To select documents that fail to match a particular query condition, use the `$not` operator. + +**Example:** The following operation selects documents that do not satisfy the specified expression, where the `stock` field is not less than `5`. + +```js +db.catalog.find({ + stock: { + $not: { + $lt: 5 + } + } +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f15"), + product: 'cup', + price: 100, + stock: 14, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['red', 'black', 'white'] } + ] + }, + { + _id: ObjectId("639ba4a0071b6bed396a8f16"), + product: 'bowl', + price: 56, + stock: 5, + discount: false, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['pink', 'white', 'red'] } + ] + } +] +``` + +## $nor + +_Syntax_: `{ $nor: [ { }, { }, ... { } ] }` + +To select documents that fail to match any of the conditions in a specified query, use the `$nor` operator. + +**Example:** Select the documents that fail to match any of these conditions: + +- `discount` field is `true` _and_ `stock` field is not `0` +- `price` field is less than or equal to `60` + +```js +db.catalog.find({ + $nor: [ + { + $and: [ + { + discount: true + }, + { + stock: { + $ne: 0 + } + } + ] + }, + { + price: { + $lte: 60 + } + } + ] +}) +``` + +The output: + +```json5 +[ + { + _id: ObjectId("639ba4a0071b6bed396a8f14"), + product: 'spoon', + price: 500, + stock: 0, + discount: true, + variation: [ + { size: ['small', 'medium', 'large'] }, + { color: ['silver', 'white'] } + ] + } +] +``` diff --git a/website/versioned_docs/version-v1.16/operators/update/_category_.yml b/website/versioned_docs/version-v1.16/operators/update/_category_.yml new file mode 100644 index 000000000000..192683635dc2 --- /dev/null +++ b/website/versioned_docs/version-v1.16/operators/update/_category_.yml @@ -0,0 +1,9 @@ +--- +label: Update Operators +position: 2 +link: + type: generated-index + slug: /update/ + description: > + The section contains all the different types of update operators available + on FerretDB diff --git a/website/versioned_docs/version-v1.16/operators/update/array-update-operators.md b/website/versioned_docs/version-v1.16/operators/update/array-update-operators.md new file mode 100644 index 000000000000..6c7c6df4bad7 --- /dev/null +++ b/website/versioned_docs/version-v1.16/operators/update/array-update-operators.md @@ -0,0 +1,215 @@ +--- +sidebar_position: 1 +--- + +# Array update operators + +Array update operators allow you to modify the elements of an array field in a document. + +| Operator | Description | +| ------------------------ | -------------------------------------------------------------------------------------------- | +| [`$push`](#push) | Adds an element to an array | +| [`$addToSet`](#addtoset) | Adds elements to a specific array as long as the element does not already exist in the array | +| [`$pop`](#pop) | Removes either the first or the last element of an array | +| [`$pullAll`](#pullall) | Removes all matching values in a specified query from an array | + +## $push + +The `$push` operator updates a document by adding an element to a specified array. +If the array does not exist, a new array is created with the element added to it. + +Insert the following document into a `store` collection: + +```js +db.store.insertMany([ + { _id: 1, items: ['pens', 'pencils', 'paper', 'erasers', 'rulers'] } +]) +``` + +**Example:** Use the `$push` operator to add an element to an existing array. + +```js +db.store.updateOne({ _id: 1 }, { $push: { items: 'markers' } }) +``` + +After the operation, the updated document looks like this: + +```json5 +[ + { + _id: 1, + items: ['pens', 'pencils', 'paper', 'erasers', 'rulers', 'markers'] + } +] +``` + +## $addToSet + +The `$addToSet` operator updates an array by adding a specified element to an array if the element does not already exist in the array. +If the specified element exists in the array, the `$addToSet` operator will not modify the array. + +Insert the following documents into a `store` collection: + +```js +db.store.insertMany([{ _id: 1, items: ['pens', 'pencils'] }]) +``` + +**Example:** Use the `$addToSet` operator to update the array with non-existing elements. + +```js +db.store.updateOne({ _id: 1 }, { $addToSet: { items: 'paper' } }) +``` + +The document is subsequently updated with the new element, as depicted below: + +```json5 +[{ _id: 1, items: ['pens', 'pencils', 'paper'] }] +``` + +**Example:** Use the `$addToSet` operator to update the array with already existing elements. + +```js +db.store.updateOne({ _id: 1 }, { $addToSet: { items: 'pens' } }) +``` + +Since the array already contains the element, there won't be any changes. + +```json5 +[{ _id: 1, items: ['pens', 'pencils', 'paper'] }] +``` + +:::note +The `$addToSet` is different from the `$push` operator which adds the element to the array either it exists or not. +::: + +**Example:** Use the `$addToSet` operator for non-existing array fields. + +If the array field does not exist in the document, the `$addToSet` operator will create the field and add the element to the array. + +```js +db.store.updateOne({ _id: 1 }, { $addToSet: { colors: 'red' } }) +``` + +The updated document looks like this: + +```json5 +[{ _id: 1, items: ['pens', 'pencils', 'paper'], colors: ['red'] }] +``` + +## $pop + +With the `$pop` operator, you can update a document by removing the first or last element of an array. +Assign a value of `-1` to remove the first element of an array, or `1` to remove the last element. + +Insert this document into a `products` collection: + +```js +db.products.insertMany([ + { _id: 1, items: ['pens', 'pencils', 'paper', 'erasers', 'rulers'] } +]) +``` + +**Example:** Use the `$pop` operator to remove the first element of an array. + +```js +db.products.updateOne({ _id: 1 }, { $pop: { items: -1 } }) +``` + +The document is subsequently updated with the first element `pens` removed, as depicted below: + +```json5 +[ + { + _id: 1, + items: ['pencils', 'paper', 'erasers', 'rulers'] + } +] +``` + +To remove the last element of the array, assign `1` as the value for the `$pop` operator. + +```js +db.products.updateOne({ _id: 1 }, { $pop: { items: 1 } }) +``` + +The updated now looks like this: + +```json5 +[ + { + _id: 1, + items: ['pencils', 'paper', 'erasers'] + } +] +``` + +## $pullAll + +The `$pullAll` operator removes all the matching elements in a specified query from an array. + +Insert the following document into a `store` collection: + +```js +db.store.insertMany([ + { _id: 1, items: ['pens', 'pencils', 'paper', 'erasers', 'rulers'] } +]) +``` + +**Example:** Use the `$pullAll` operator to remove multiple elements from an array. + +```js +db.store.updateOne( + { _id: 1 }, + { $pullAll: { items: ['pens', 'pencils', 'paper'] } } +) +``` + +After removing all instances of the specified array elements, the document is updated as follows: + +```json5 +[ + { + _id: 1, + items: ['erasers', 'rulers'] + } +] +``` + +**Example:** Use the `$pullAll` operator to remove array of objects from an array. + +Insert the following document into a `fruits` collection: + +```js +db.fruits.insertMany([ + { + _id: 1, + fruits: [ + { type: 'apple', color: 'red' }, + { type: 'banana', color: 'yellow' }, + { type: 'orange', color: 'orange' } + ] + } +]) +``` + +The following query uses the `$pullAll` to remove all matching array objects from the specified document. + +```js +db.fruits.update( + { _id: 1 }, + { + $pullAll: { + fruits: [ + { type: 'apple', color: 'red' }, + { type: 'banana', color: 'yellow' } + ] + } + } +) +``` + +The updated document now looks like this: + +```json5 +[{ _id: 1, fruits: [{ type: 'orange', color: 'orange' }] }] +``` diff --git a/website/versioned_docs/version-v1.16/operators/update/field-update-operators.md b/website/versioned_docs/version-v1.16/operators/update/field-update-operators.md new file mode 100644 index 000000000000..303615272247 --- /dev/null +++ b/website/versioned_docs/version-v1.16/operators/update/field-update-operators.md @@ -0,0 +1,370 @@ +--- +sidebar_position: 1 +--- + +# Field update operators + +Field update operators allow you to modify the value of a specified field in a document when certain conditions are met. + +| Operator | Description | +| ------------------------------ | ------------------------------------------------------------------------------------------- | +| [`$set`](#set) | Assigns the value of a given field | +| [`$unset`](#unset) | Deletes the records of a field from a document | +| [`$inc`](#inc) | Increments a given field's value | +| [`$mul`](#mul) | Multiplies a given field's value by a specific value | +| [`$rename`](#rename) | Renames a given field with another name | +| [`$min`](#min) | Updates a particular field only when the specified value is lesser than the specified value | +| [`$max`](#max) | Updates a particular field only when the specified value is higher than the specified value | +| [`$currentDate`](#currentdate) | Specifies the current date and time as the value of a given field | +| [`$setOnInsert`](#setoninsert) | Inserts elements into an array only if they don't already exist | + +For the examples in this section, insert the following documents into the `employees` collection: + +```js +db.employee.insertOne({ + name: 'John Doe', + age: 35, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'Anytown', + state: 'CA' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: new Date('2021-01-01'), + endDate: null +}) +``` + +## $set + +The `$set` operator updates the value of a specified field and if the field does not exist, the `$set` operator creates a new field and adds it to the document. + +**Example:** The below query is an example that updates the value of the `city` field in the `address` embedded document. + +```js +db.employee.updateOne( + { name: 'John Doe' }, + { + $set: { + 'address.city': 'New York', + 'address.zip': '12345' + } + } +) +``` + +The above query updates the value of the `city` field in the `address` embedded document and adds a new field `zip` to it. + +This is the updated document: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 35, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA', + zip: '12345' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $unset + +The `$unset` operator deletes the specified field from a document and if the field is not present, the `$unset` operator will not do anything. + +**Example:** The below query deletes the `zip` field from the embedded document `address`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $unset: { 'address.zip': '' } }) +``` + +Below is the updated document, without the `zip` field: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 35, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $inc + +The `$inc` operator increments the value of a given field by a specified amount. +If the field is non-existent in the document, the `$inc` operator creates a new field and adds it to the document, setting the value to the specified increment amount. + +**Example:** The below query increments the value of the `age` field by `1`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $inc: { age: 1 } }) +``` + +The updated document looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 36, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 50000, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $mul + +The `$mul` operator multiplies the value of a given field by a specified amount. +Similar to all most of the other field update operators, if the field is non-existent in the document, the `$mul` operator creates a new one and sets the value to `0`. + +**Example:** This example query multiplies the value of the `salary` field by `25%`, represented as `1.25`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $mul: { salary: 1.25 } }) +``` + +The updated record looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 36, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + jobTitle: 'Manager', + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null + } +] +``` + +## $rename + +The `$rename` operator renames a given field to another name. + +**Example:** The query below updates the `employee` collection and renames the `jobTitle` field to `title`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $rename: { jobTitle: 'title' } }) +``` + +The updated document looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 36, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null, + title: 'Manager' + } +] +``` + +## $min + +The `$min` operator compares a specified value with the value of the given field and updates the field to the specified value if the specified value is less than the current value of the field. + +**Example:** The below query updates the value of the `age` field to `30` as long as the current value is less than `30`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $min: { age: 30 } }) +``` + +Since `30` is less than `36`, the value of the `age` field is updated to `30`. +The updated document now looks like this: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 30, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null, + title: 'Manager' + } +] +``` + +## $max + +The `$max` operator compares a specified value with the value of the given field and updates the field to the specified value if the specified value is greater than the current value of the field. + +**Example:** The below query updates the value of the `age` field to `40` as long as the current value is greater than `40`. + +```js +db.employee.updateOne({ name: 'John Doe' }, { $max: { age: 40 } }) +``` + +This is what the updated document looks like: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 40, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { street: '123 Main St', city: 'New York', state: 'CA' }, + salary: 62500, + startDate: ISODate('2021-01-01T00:00:00.000Z'), + endDate: null, + height: 0, + title: 'Manager' + } +] +``` + +## $currentDate + +The `$currentDate` operator assigns the current date as the value of a given field. +This can be as a date or timestamp. + +**Example:** To update the `startDate` field with the current date, use the following query: + +```js +db.employee.updateOne( + { name: 'John Doe' }, + { $currentDate: { startDate: true } } +) +``` + +This is the document after the update: + +```json5 +[ + { + _id: ObjectId("640a603558955e0e2b57c00d"), + name: 'John Doe', + age: 40, + email: 'johndoe@example.com', + phone: '123-456-7890', + address: { + street: '123 Main St', + city: 'New York', + state: 'CA' + }, + salary: 62500, + startDate: ISODate('2023-03-10T01:26:35.606Z'), + endDate: null, + height: 0, + title: 'Manager' + } +] +``` + +## $setOnInsert + +The `$setOnInsert` operator sets the value of a given field if the document is inserted into a collection during an upsert operation. +If there is no insertion, the `$setOnInsert` operator does nothing. + +**Example:** Let's say you have a `stocks` collection that stores information about different stocks, and you want to update the stock information or add a new stock if it doesn't exist. +Here's an example of how `$SetOnInsert` works differently from `$set`. + +Using `$set`: + +```js +db.stocks.update( + { symbol: 'AAPL' }, + { + $set: { + price: 150, + lastUpdate: new Date() + } + }, + { upsert: true } +) +``` + +This query checks for a stock with the symbol "AAPL". +If it finds the stock, it updates the `price` and `lastUpdate` fields. +If it doesn't find the stock, it inserts a new document with the `symbol`, `price`, and `lastUpdate` fields. + +Using `$setOnInsert`: + +```js +db.stocks.update( + { symbol: 'AAPL' }, + { + $set: { price: 150 }, + $setOnInsert: { + companyName: 'Apple Inc.', + createdAt: new Date() + } + }, + { upsert: true } +) +``` + +This query also checks for a stock with the symbol "AAPL". +If it finds the stock, it updates only the `price` field. +If it doesn't find the stock, it inserts a new document with the `symbol`, `price`, `companyName`, and `createdAt` fields. +The `companyName` and `createdAt` fields are only added when a new document is inserted. + +Comparing both examples, the `$set` operator updates or inserts the specified fields in both cases. +On the other hand, the `$setOnInsert` operator sets the specified fields only when a new document is inserted, leaving existing documents unchanged. diff --git a/website/versioned_docs/version-v1.16/pushdown.md b/website/versioned_docs/version-v1.16/pushdown.md new file mode 100644 index 000000000000..c6f0f228cfcf --- /dev/null +++ b/website/versioned_docs/version-v1.16/pushdown.md @@ -0,0 +1,54 @@ +--- +sidebar_position: 7 +hide_table_of_contents: true +--- + +# Query pushdown + +**Query pushdown** is the method of optimizing a query by reducing the amount of data read and processed. +It saves memory space, network bandwidth, and reduces the query execution time by moving some parts +of the query execution closer to the data source. + +Initially FerretDB retrieved all data related to queried collection, and applies filters on its own, making +it possible to implement complex logic safely and quickly. +To make this process more efficient, we minimize the amount of incoming data, by applying WHERE clause on SQL queries. + +:::info +You can learn more about query pushdown in our [blog post](https://blog.ferretdb.io/ferretdb-fetches-data-query-pushdown/). +::: + +## Supported types and operators + +The following table shows all operators and types that FerretDB pushdowns on PostgreSQL backend. +If filter uses type and operator, that's marked as pushdown-supported on this list, +FerretDB will prefetch less data, resulting with more performent query. + +If your application requires better performance for specific operation, +feel free to share this with us in our [community](/#community)! + +:::tip +As query pushdown allows developers to implement query optimizations separately from the features, +the table will be updated frequently. +::: + + + + +| | Object | Array | Double | String | Binary | ObjectID | Boolean | Date | Null | Regex | Integer | Timestamp | Long | +| ------ | ------ | ----- | ----------------------- | ------ | ------ | -------- | ------- | ---- | ---- | ----- | ------- | --------- | ----------------------- | +| `=` | ✖️ | ✖️ | ⚠️ [[1]](#1) | ✅ | ✖️ | ✅ | ✅ | ✅ | ✖️ | ✖️ | ✅ | ✖️ | ⚠️ [[1]](#1) | +| `$eq` | ✖️ | ✖️ | ⚠️ [[1]](#1) | ✅ | ✖️ | ✅ | ✅ | ✅ | ✖️ | ✖️ | ✅ | ✖️ | ⚠️ [[1]](#1) | +| `$gt` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$gte` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$lt` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$lte` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$in` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | +| `$ne` | ✖️ | ✖️ | ⚠️ [[1]](#1) | ✅ | ✖️ | ✅ | ✅ | ✅ | ✖️ | ✖️ | ✅ | ✖️ | ⚠️ [[1]](#1) | +| `$nin` | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | + +###### [1] {#1} + +Numbers outside the range of the safe IEEE 754 precision (`< -9007199254740991.0, 9007199254740991.0 >`), +will prefetch all numbers larger/smaller than max/min value of the range. + + diff --git a/website/versioned_docs/version-v1.16/quickstart-guide/_category_.yml b/website/versioned_docs/version-v1.16/quickstart-guide/_category_.yml new file mode 100644 index 000000000000..ff1c769eb893 --- /dev/null +++ b/website/versioned_docs/version-v1.16/quickstart-guide/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Get Started +position: 3 +link: + type: generated-index + slug: /quickstart-guide/ # referenced in README.md + description: > + Learn to install FerretDB on your local machine diff --git a/website/versioned_docs/version-v1.16/quickstart-guide/deb.md b/website/versioned_docs/version-v1.16/quickstart-guide/deb.md new file mode 100644 index 000000000000..d3c9e4f4c0ba --- /dev/null +++ b/website/versioned_docs/version-v1.16/quickstart-guide/deb.md @@ -0,0 +1,37 @@ +--- +sidebar_position: 2 +--- + +# DEB package + +To install the `.deb` packages for FerretDB on your Debian, Ubuntu, and other `.deb`-based systems, +you can use `dpkg` tool. + +Download the latest FerretDB `.deb` package from [our release pages](https://github.com/FerretDB/FerretDB/releases/latest), +rename it to `ferretdb.deb`, +then run the following command in your terminal: + +```sh +sudo dpkg -i ferretdb.deb +``` + +You can check that FerretDB was installed by running + +```sh +ferretdb --version +``` + +FerretDB does not automatically install PostgreSQL or other backends. +To install PostgreSQL, run the following commands: + +```sh +sudo apt update +sudo apt install -y postgresql +``` + +Currently, our `.deb` package does not provide a SystemD unit for starting FerretDB automatically. +You have to do it manually by running `ferretdb` binary with the [correct flags](../configuration/flags.md). + +Find out more about: + +- [getting logs](../configuration/observability.md#binary-executable-logs). diff --git a/website/versioned_docs/version-v1.16/quickstart-guide/docker.md b/website/versioned_docs/version-v1.16/quickstart-guide/docker.md new file mode 100644 index 000000000000..0a3e0d9323cf --- /dev/null +++ b/website/versioned_docs/version-v1.16/quickstart-guide/docker.md @@ -0,0 +1,138 @@ +--- +sidebar_position: 1 +slug: /quickstart-guide/docker/ # referenced in README.md +description: How to set up FerretDB using Docker +--- + +# Docker + +We provide three Docker images for various deployments: +**"all-in-one"** for quick testing and experiments, +**a development image** for debugging problems, +and **a production image** for all other cases. + +All-in-one image is documented in the +[README.md file in the repository](https://github.com/FerretDB/FerretDB#quickstart). +The rest are covered below. + +## Production image + +Our [production image](https://ghcr.io/ferretdb/ferretdb) `ghcr.io/ferretdb/ferretdb` +is recommended for most deployments. +It does not include PostgreSQL or other backends, so you must run them separately. +You can do that with Docker Compose, Kubernetes, or other means. + +### PostgreSQL Setup with Docker Compose + +The following steps describe a quick local setup: + +1. Store the following in the `docker-compose.yml` file: + + ```yaml + services: + postgres: + image: postgres + environment: + - POSTGRES_USER=username + - POSTGRES_PASSWORD=password + - POSTGRES_DB=ferretdb + volumes: + - ./data:/var/lib/postgresql/data + + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27017:27017 + environment: + - FERRETDB_POSTGRESQL_URL=postgres://postgres:5432/ferretdb + + networks: + default: + name: ferretdb + ``` + + `postgres` container runs PostgreSQL that would store data in the `./data` directory on the host. + `ferretdb` runs FerretDB. + +2. Start services with `docker compose up -d`. +3. If you have `mongosh` installed, just run it to connect to FerretDB. + It will use credentials passed in `mongosh` flags or MongoDB URI to authenticate to the PostgreSQL database. + You'll also need to set `authMechanism` to `PLAIN`. + The example URI would look like: + + ```text + mongodb://username:password@127.0.0.1/ferretdb?authMechanism=PLAIN + ``` + + See [Authentication](../security/authentication.md) and + [Securing connection with TLS](../security/tls-connections.md) for more details. + + If you don't have `mongosh`, run the following command to run it inside the temporary MongoDB container, + attaching to the same Docker network: + + ```sh + docker run --rm -it --network=ferretdb --entrypoint=mongosh mongo \ + "mongodb://username:password@ferretdb/ferretdb?authMechanism=PLAIN" + ``` + +You can improve that setup by: + +- [securing connections with TLS](../security/tls-connections.md); +- adding backups. + +Find out more about: + +- [getting logs](../configuration/observability.md#docker-logs). + +### SQLite Setup with Docker Compose + +The following steps describe the setup for SQLite: + +1. Store the following in the `docker-compose.yml` file: + + ```yaml + services: + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27017:27017 + environment: + - FERRETDB_HANDLER=sqlite + volumes: + - ./state:/state + + networks: + default: + name: ferretdb + ``` + + Unlike PostgreSQL, SQLite operates serverlessly so it does not require its own service in Docker Compose. + :::note + At the moment, authentication is not available for the SQLite backend ([See Issue here](https://github.com/FerretDB/FerretDB/issues/3008)). + ::: + +2. Start services with `docker compose up -d`. +3. If you have `mongosh` installed, just run it to connect to FerretDB. + + The example URI would look like: + + ```text + mongodb://127.0.0.1:27017/ferretdb + ``` + + Similarly, if you don't have `mongosh` installed, run this command to run it inside the temporary MongoDB container, attaching to the same Docker network: + + ```text + docker run --rm -it --network=ferretdb --entrypoint=mongosh mongo \ + "mongodb://ferretdb/ferretdb" + ``` + +## Development image + +The [development image](https://ghcr.io/ferretdb/ferretdb-dev) `ghcr.io/ferretdb/ferretdb-dev` +contains the [debug build](https://pkg.go.dev/github.com/FerretDB/FerretDB/build/version#hdr-Debug_builds) +of FerretDB with test coverage instrumentation, race detector, +and other changes that make it more suitable for debugging problems. +It can be used exactly the same way as the production image, as described above. diff --git a/website/versioned_docs/version-v1.16/quickstart-guide/go.md b/website/versioned_docs/version-v1.16/quickstart-guide/go.md new file mode 100644 index 000000000000..c3a5c313aa29 --- /dev/null +++ b/website/versioned_docs/version-v1.16/quickstart-guide/go.md @@ -0,0 +1,11 @@ +--- +sidebar_position: 6 +--- + +# Go + +See https://pkg.go.dev/github.com/FerretDB/FerretDB/ferretdb. + +_This section is not currently available. +You can help FerretDB by contributing to this section. +Click the **Edit this page** link below to get started_. diff --git a/website/versioned_docs/version-v1.16/quickstart-guide/macos.md b/website/versioned_docs/version-v1.16/quickstart-guide/macos.md new file mode 100644 index 000000000000..8cd14d51dbc4 --- /dev/null +++ b/website/versioned_docs/version-v1.16/quickstart-guide/macos.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 4 +--- + +# macOS + +_This section is not currently available. +You can help FerretDB by contributing to this section. +Click the **Edit this page** link below to get started_. diff --git a/website/versioned_docs/version-v1.16/quickstart-guide/rpm.md b/website/versioned_docs/version-v1.16/quickstart-guide/rpm.md new file mode 100644 index 000000000000..8b7c2918771b --- /dev/null +++ b/website/versioned_docs/version-v1.16/quickstart-guide/rpm.md @@ -0,0 +1,36 @@ +--- +sidebar_position: 3 +--- + +# RPM package + +To install the `.rpm` packages for FerretDB on your RHEL, CentOS, and other `.rpm`-based systems, +you can use `rpm` tool. + +Download the latest FerretDB `.rpm` package from [our release pages](https://github.com/FerretDB/FerretDB/releases/latest), +rename it to `ferretdb.rpm`, +then run the following command in your terminal: + +```sh +sudo rpm -i ferretdb.rpm +``` + +You can check that FerretDB was installed by running + +```sh +ferretdb --version +``` + +FerretDB does not automatically install PostgreSQL or other backends. +To install PostgreSQL, run the following commands: + +```sh +sudo yum install -y postgresql +``` + +Currently, our `.rpm` package does not provide a SystemD unit for starting FerretDB automatically. +You have to do it manually by running `ferretdb` binary with the [correct flags](../configuration/flags.md). + +Find out more about: + +- [getting logs](../configuration/observability.md#binary-executable-logs). diff --git a/website/versioned_docs/version-v1.16/quickstart-guide/windows.md b/website/versioned_docs/version-v1.16/quickstart-guide/windows.md new file mode 100644 index 000000000000..7f6b7cb8ac49 --- /dev/null +++ b/website/versioned_docs/version-v1.16/quickstart-guide/windows.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 5 +--- + +# Windows + +_This section is not currently available. +You can help FerretDB by contributing to this section. +Click the **Edit this page** link below to get started_. diff --git a/website/versioned_docs/version-v1.16/reference/_category_.yml b/website/versioned_docs/version-v1.16/reference/_category_.yml new file mode 100644 index 000000000000..72f94748ed01 --- /dev/null +++ b/website/versioned_docs/version-v1.16/reference/_category_.yml @@ -0,0 +1,8 @@ +--- +label: Reference +position: 14 +link: + type: generated-index + slug: /reference/ + description: > + Reference pages on diagnostic commands, operators, glossary, etc. diff --git a/website/versioned_docs/version-v1.16/reference/glossary.md b/website/versioned_docs/version-v1.16/reference/glossary.md new file mode 100644 index 000000000000..36acaf43266e --- /dev/null +++ b/website/versioned_docs/version-v1.16/reference/glossary.md @@ -0,0 +1,156 @@ +--- +sidebar_position: 2 +--- + +# Glossary + +## List of FerretDB terminologies + +_This section contains a list of common terminologies related to FerretDB_. + +### A + +#### aggregation + +A way of processing documents in a collection and passing them through various operations or stages. +See [list of supported aggregation operations and commands here](supported-commands.md#aggregation-pipelines). + +#### aggregation pipeline + +A set of operators that lets you perform complex operations that aggregate and summarize values. +See [list of supported aggregation pipeline operators](supported-commands.md#aggregation-pipeline-operators) here. + +--- + +### B + +#### Beacon + +The telemetry service of FerretDB. +See [telemetry](../telemetry.md) for more details. + +#### BSON + +BSON is a serialized binary file format for storing JSON-like documents. + +#### BSON types + +The list of types that the BSON format supports. +BSON offers support for additional data types compared to JSON, such as `timestamp`, `date`, `ObjectId`, and `binary`. + +--- + +### C + +#### collection + +A group of documents in a non-relational database. +It is comparable to a table in a relational database. + +#### CRUD + +The four basic operations of a database: Create, Read, Update, and Delete. +See [Basic FerretDB CRUD operations here](../basic-operations/index.md). + +--- + +### D + +#### database + +An organized repository for collections containing its own sets of documents, and data. + +#### database command + +The set of commands in FerretDB. +For more information, see [supported commands](supported-commands.md) for more details. + +#### document + +A record in a collection that comprises key-value pairs. +See [Documents](../understanding-ferretdb.md#documents) for more. + +#### dot notation + +Dot notation is used to reference or access the elements in an array or in an embedded document. +See [dot notation](../understanding-ferretdb.md#dot-notation) for more details. + +--- + +### F + +#### field + +Similar to columns in a relational database. +They are represented as field name-value pairs and describe the kind of data in a document. + +--- + +### I + +#### index + +A data structure used for identifying and querying records in a collection. +It helps to limit the number of documents to search through or inspect in a collection. +Examples include `_id` index, user-defined index, hashed index, and partial index. +See [Indexes](../indexes.md) for more. + +--- + +### J + +#### JSON + +An acronym for JavaScript Object Notation. +It is a structured data format with human-readable text to store data objects composed of attribute-value pairs. + +#### JSONB + +JSONB is a data type of PostgreSQL that stores JSON data as a decomposed binary format. + +#### ObjectId + +A defining 12-byte type that ensures singularity and uniques within a collection and are used to represent the default values for the `_id` fields. + +#### operator + +A keyword that starts with a `$` character to query, update, or transform data. + +--- + +### O + +#### Operation modes + +FerretDB utilizes operation modes to define its approach in handling incoming requests, serving purposes such as testing, debugging, and bug reporting. +By default, FerretDB operates in `normal` mode. +See [Operation modes](../configuration/operation-modes.md) for more details. + +--- + +### P + +#### primary key + +An immutable identifier for a record. +The primary key of a documents is stored in the `_id` field, which typically contains the `ObjectId`. + +#### proxy + +Proxy is any MongoDB-compatible database that is running in parallel with FerretDB. +It's used to test differences between FerretDB and other databases. +See [Operation modes](../configuration/operation-modes.md) for more details. + +#### PostgreSQL + +An open source relational database. +FerretDB uses PostgreSQL as a database engine. + +### S + +#### SQLite + +SQLite is a self-contained, serverless system ideal for lightweight applications. +FerretDB now offers SQLite backend support. + +--- diff --git a/website/versioned_docs/version-v1.16/reference/supported-commands.md b/website/versioned_docs/version-v1.16/reference/supported-commands.md new file mode 100644 index 000000000000..8e47062c8477 --- /dev/null +++ b/website/versioned_docs/version-v1.16/reference/supported-commands.md @@ -0,0 +1,727 @@ +--- +sidebar_position: 1 +description: This is a list of all supported commands in FerretDB +--- + +# Supported commands + + + +## Query commands + +| Command | Argument | Status | Comments | +| --------------- | -------------------------- | ------ | --------------------------------------------------------- | +| `delete` | | ✅ | Basic command is fully supported | +| | `deletes` | ✅ | | +| | `comment` | ⚠️ | | +| | `let` | ⚠️ | Unimplemented | +| | `ordered` | ✅ | | +| | `writeConcern` | ⚠️ | Ignored | +| | `q` | ✅ | | +| | `limit` | ✅ | | +| | `collation` | ❌ | Unimplemented | +| | `hint` | ⚠️ | Ignored | +| `find` | | ✅ | Basic command is fully supported | +| | `filter` | ✅ | | +| | `sort` | ✅ | | +| | `projection` | ✅ | Basic projections with fields are supported | +| | `hint` | ⚠️ | Ignored | +| | `skip` | ⚠️ | | +| | `limit` | ✅ | | +| | `batchSize` | ✅ | | +| | `singleBatch` | ✅ | | +| | `comment` | ⚠️ | | +| | `maxTimeMS` | ✅ | | +| | `readConcern` | ⚠️ | Ignored | +| | `max` | ⚠️ | Ignored | +| | `min` | ⚠️ | Ignored | +| | `returnKey` | ❌ | Unimplemented | +| | `showRecordId` | ✅ | | +| | `tailable` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2283) | +| | `oplogReplay` | ❌ | Unimplemented | +| | `noCursorTimeout` | ❌ | Unimplemented | +| | `awaitData` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2283) | +| | `allowPartialResults` | ❌ | Unimplemented | +| | `collation` | ❌ | Unimplemented | +| | `allowDiskUse` | ⚠️ | Ignored | +| | `let` | ❌ | Unimplemented | +| `findAndModify` | | ✅ | Basic command is fully supported | +| | `query` | ✅ | | +| | `sort` | ✅ | | +| | `remove` | ✅ | | +| | `update` | ✅ | | +| | `new` | ✅ | | +| | `upsert` | ✅ | | +| | `bypassDocumentValidation` | ⚠️ | Ignored | +| | `writeConcern` | ⚠️ | Ignored | +| | `maxTimeMS` | ✅ | | +| | `collation` | ❌ | Unimplemented | +| | `arrayFilters` | ❌ | Unimplemented | +| | `hint` | ⚠️ | Ignored | +| | `comment` | ⚠️ | | +| | `let` | ⚠️ | Unimplemented | +| `getMore` | | ✅ | Basic command is fully supported | +| | `batchSize` | ✅ | | +| | `maxTimeMS` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2984) | +| | `comment` | ⚠️ | Unimplemented | +| `insert` | | ✅ | Basic command is fully supported | +| | `documents` | ✅ | | +| | `ordered` | ✅ | | +| | `bypassDocumentValidation` | ⚠️ | Ignored | +| | `comment` | ⚠️ | Ignored | +| `update` | | ✅ | Basic command is fully supported | +| | `updates` | ✅ | | +| | `ordered` | ⚠️ | Ignored | +| | `writeConcern` | ⚠️ | Ignored | +| | `bypassDocumentValidation` | ⚠️ | Ignored | +| | `comment` | ⚠️ | | +| | `let` | ⚠️ | Unimplemented | +| | `q` | ✅ | | +| | `u` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2742) | +| | `c` | ⚠️ | Unimplemented | +| | `upsert` | ✅ | | +| | `multi` | ✅ | | +| | `collation` | ❌ | Unimplemented | +| | `arrayFilters` | ⚠️ | Unimplemented | +| | `hint` | ⚠️ | Ignored | + +### Update Operators + +The following operators and modifiers are available in the `update` and `findAndModify` commands. + +| Operator | Modifier | Status | Comments | +| ----------------- | ----------- | ------ | -------------------------------------------------------- | +| `$currentDate` | | ✅ | | +| `$inc` | | ✅ | | +| `$min` | | ✅ | | +| `$max` | | ✅ | | +| `$mul` | | ✅ | | +| `$rename` | | ✅ | | +| `$set` | | ✅ | | +| `$setOnInsert` | | ✅ | | +| `$unset` | | ✅ | | +| `$` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/822) | +| `$[]` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/823) | +| `$[]` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/824) | +| `$addToSet` | | ✅️ | | +| `$pop` | | ✅ | | +| `$pull` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/826) | +| `$push` | | ✅️ | | +| `$pullAll` | | ✅️ | | +| | `$each` | ✅️ | | +| | `$position` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/829) | +| | `$slice` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/830) | +| | `$sort` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/831) | +| | `$bit` | ✅️ | | + +### Projection Operators + +The following operators are available in the `find` command `projection` argument. + +| Operator | Status | Comments | +| ------------ | ------ | --------------------------------------------------------- | +| `$` | ✅️ | | +| `$elemMatch` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1710) | +| `$meta` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1712) | +| `$slice` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1711) | + +## Query Plan Cache Commands + +Related [issue](https://github.com/FerretDB/FerretDB/issues/78). + +| Command | Argument | Status | Comments | +| ----------------------- | ------------ | ------ | --------------------------------------------------------- | +| `planCacheClear` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1502) | +| | `query` | ⚠️ | | +| | `projection` | ⚠️ | | +| | `sort` | ⚠️ | | +| | `comment` | ⚠️ | | +| `planCacheClearFilters` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1503) | +| | `query` | ⚠️ | | +| | `sort` | ⚠️ | | +| | `projection` | ⚠️ | | +| | `collation` | ❌ | Unimplemented | +| | `comment` | ⚠️ | | +| `planCacheListFilters` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1504) | +| | `comment` | ⚠️ | | +| `planCacheSetFilter` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1505) | +| | `query` | ⚠️ | | +| | `sort` | ⚠️ | | +| | `projection` | ⚠️ | | +| | `collation` | ❌ | Unimplemented | +| | `indexes` | ⚠️ | | +| | `comment` | ⚠️ | | + +## Free Monitoring Commands + +| Command | Argument | Status | Comments | +| ------------------------- | ------------------- | ------ | ---------------------------------------------------------- | +| `setFreeMonitoring` | | ✅ | [Telemetry reporting](../telemetry.md) | +| | `action: "enable"` | ✅ | [`--telemetry=enable`](../telemetry.md#enable-telemetry) | +| | `action: "disable"` | ✅ | [`--telemetry=disable`](../telemetry.md#disable-telemetry) | +| `getFreeMonitoringStatus` | | ✅ | | + +## Database Operations + +### User Management Commands + +| Command | Argument | Status | Comments | +| -------------------------- | -------------------------------- | ------ | --------------------------------------------------------- | +| `createUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1491) | +| | `pwd` | ⚠️ | | +| | `customData` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `mechanisms` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropAllUsersFromDatabase` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1492) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1493) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `grantRolesToUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1494) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `revokeRolesFromUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1495) | +| | `roles` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `updateUser` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1496) | +| | `pwd` | ⚠️ | | +| | `customData` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `mechanisms` | ⚠️ | | +| | `digestPassword` | ⚠️ | | +| | `comment` | ⚠️ | | +| `usersInfo` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1497) | +| | `showCredentials` | ⚠️ | | +| | `showCustomData` | ⚠️ | | +| | `showPrivileges` | ⚠️ | | +| | `showAuthenticationRestrictions` | ⚠️ | | +| | `filter` | ⚠️ | | +| | `comment` | ⚠️ | | + +### Authentication Commands + +| Command | Argument | Status | Comments | +| -------------- | -------- | ------ | --------------------------------------------------------- | +| `authenticate` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1731) | +| `getnonce` | | ❌ | Deprecated | +| `logout` | | ✅ | | +| `saslStart` | | ✅ | | + +### Role Management Commands + +| Command | Argument | Status | Comments | +| -------------------------- | ---------------------------- | ------ | --------------------------------------------------------- | +| `createRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1528) | +| | `privileges` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1529) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `dropAllRolesFromDatabase` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1530) | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `grantPrivilegesToRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1531) | +| | `privileges` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `grantRolesToRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1532) | +| | `roles` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `invalidateUserCache` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1533) | +| `revokePrivilegesFromRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1534) | +| | `privileges` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `revokeRolesFromRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1535) | +| | `roles` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | +| `rolesInfo` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1536) | +| | `showPrivileges` | ⚠️ | | +| | `showBuiltinRoles` | ⚠️ | | +| | `comment` | ⚠️ | | +| `updateRole` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1537) | +| | `privileges` | ⚠️ | | +| | `roles` | ⚠️ | | +| | `authenticationRestrictions` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `comment` | ⚠️ | | + +## Session Commands + +Related [issue](https://github.com/FerretDB/FerretDB/issues/8). + +Related [issue](https://github.com/FerretDB/FerretDB/issues/153). + +| Command | Argument | Status | Comments | +| -------------------------- | -------------- | ------ | --------------------------------------------------------- | +| `abortTransaction` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1547) | +| | `txnNumber` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `autocommit` | ⚠️ | | +| | `comment` | ⚠️ | | +| `commitTransaction` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1548) | +| | `txnNumber` | ⚠️ | | +| | `writeConcern` | ⚠️ | | +| | `autocommit` | ⚠️ | | +| | `comment` | ⚠️ | | +| `endSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1549) | +| `killAllSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1550) | +| `killAllSessionsByPattern` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1551) | +| `killSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1552) | +| `refreshSessions` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1553) | +| `startSession` | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1554) | + +## Aggregation pipelines + +Related [issue](https://github.com/FerretDB/FerretDB/issues/1917). + +| Command | Argument | Status | Comments | +| ----------- | -------- | ------ | -------- | +| `aggregate` | | ✅️ | | +| `count` | | ✅ | | +| `distinct` | | ✅ | | + +### Aggregation pipeline stages + +| Stage | Status | Comments | +| -------------------- | ------ | --------------------------------------------------------- | +| `$addFields` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/1413) | +| `$bucket` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1414) | +| `$bucketAuto` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1414) | +| `$changeStream` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1415) | +| `$changeStream` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1415) | +| `$collStats` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2447) | +| `$count` | ✅️ | | +| `$currentOp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1444) | +| `$densify` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1418) | +| `$documents` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1419) | +| `$documents` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1419) | +| `$facet` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1420) | +| `$fill` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1421) | +| `$geoNear` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1412) | +| `$graphLookup` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1422) | +| `$group` | ✅️ | | +| `$indexStats` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1424) | +| `$limit` | ✅️ | | +| `$listLocalSessions` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1426) | +| `$listSessions` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1426) | +| `$lookup` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1427) | +| `$match` | ✅ | | +| `$merge` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1429) | +| `$out` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1430) | +| `$planCacheStats` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1431) | +| `$project` | ✅ | | +| `$redact` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1433) | +| `$replaceRoot` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1434) | +| `$replaceWith` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1434) | +| `$sample` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1435) | +| `$search` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1436) | +| `$searchMeta` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1436) | +| `$set` | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/1413) | +| `$setWindowFields` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1437) | +| `$skip` | ✅️ | | +| `$sort` | ✅️ | | +| `$sortByCount` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1440) | +| `$unionWith` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1441) | +| `$unset` | ✅️ | | +| `$unwind` | ✅️ | | + +### Aggregation pipeline operators + +| Operator | Status | Comments | +| ------------------------- | ------ | --------------------------------------------------------- | +| `$abs` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$accumulator` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$acos` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$acosh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$add` (arithmetic) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$add` (date) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$addToSet` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$allElementsTrue` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$and` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1455) | +| `$anyElementTrue` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$arrayElemAt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$arrayToObject` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$asin` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$asinh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$atan` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$atan2` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$atanh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$avg` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$binarySize` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1459) | +| `$bottom` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$bottomN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$bsonSize` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1459) | +| `$ceil` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$cmp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$concat` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$concatArrays` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$cond` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1457) | +| `$convert` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$cos` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$cosh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$count` | ✅️ | | +| `$covariancePop` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$covarianceSamp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$dateAdd` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateDiff` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateFromParts` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateFromString` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateSubtract` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateToParts` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateToString` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dateTrunc` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dayOfMonth` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dayOfWeek` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$dayOfYear` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$degreesToRadians` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$denseRank` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$derivative` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$divide` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$documentNumber` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$eq` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$exp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$expMovingAvg` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$filter` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$first` (accumulator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$first` (array operator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$firstN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$floor` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$function` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1458) | +| `$getField` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1471) | +| `$gt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$gte` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$hour` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$ifNull` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1457) | +| `$in` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$indexOfArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$indexOfBytes` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$indexOfCP` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$integral` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$isArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$isNumber` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$isoDayOfWeek` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$isoWeek` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$isoWeekYear` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$last` (accumulator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$last` (array operator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$lastN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$let` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1469) | +| `$linearFill` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$literal` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1470) | +| `$ln` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$locf` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$log` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$log10` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$lt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$lte` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$ltrim` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$map` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$max` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$maxN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$mergeObjects` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$meta` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$millisecond` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$min` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$minN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$minute` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$mod` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$month` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$multiply` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$ne` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1456) | +| `$not` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1455) | +| `$objectToArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1461) | +| `$or` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1455) | +| `$pow` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$push` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$radiansToDegrees` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$rand` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/541) | +| `$range` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$rank` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$reduce` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$regexFind` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$regexFindAll` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$regexMatch` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$replaceAll` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$replaceOne` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$reverseArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$round` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$rtrim` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$sampleRate` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1472) | +| `$second` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$setDifference` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setEquals` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setField` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1461) | +| `$setIntersection` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setIsSubset` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$setUnion` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1462) | +| `$shift` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1468) | +| `$sin` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$sinh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$size` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$slice` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$sortArray` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | +| `$split` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$sqrt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$stdDevPop` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$stdDevSamp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$strcasecmp` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$strLenBytes` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$strLenCP` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$substr` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$substrBytes` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$substrCP` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$subtract` (arithmetic) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$subtract` (date) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$sum` (accumulator) | ✅️ | | +| `$sum` (operator) | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2680) | +| `$switch` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1457) | +| `$tan` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$tanh` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1465) | +| `$toBool` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toDate` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$toDecimal` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toDouble` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toInt` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toLong` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toLower` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$toObjectId` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$top` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$topN` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1467) | +| `$toString` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$toUpper` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$trim` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1463) | +| `$trunc` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1453) | +| `$tsIncrement` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1464) | +| `$tsSecond` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1464) | +| `$type` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1466) | +| `$unsetField` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1461) | +| `$week` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$year` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1460) | +| `$zip` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1454) | + +## Administration commands + +| Command | Argument / Option | Property | Status | Comments | +| --------------------------------- | ------------------------------ | ------------------------- | ------ | --------------------------------------------------------- | +| `cloneCollectionAsCapped` | | | ❌ | | +| | `toCollection` | | ⚠️ | | +| | `size` | | ⚠️ | | +| | `writeConcern` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `collMod` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1510) | +| | `index` | | ⚠️ | | +| | | `keyPattern` | ⚠️ | | +| | | `name` | ⚠️ | | +| | | `expireAfterSeconds` | ⚠️ | | +| | | `hidden` | ⚠️ | | +| | | `prepareUnique` | ⚠️ | | +| | | `unique` | ⚠️ | | +| | `validator` | | ⚠️ | | +| | | `validationLevel` | ⚠️ | | +| | | `validationAction` | ⚠️ | | +| | `viewOn` (Views) | | ⚠️ | | +| | `pipeline` (Views) | | ⚠️ | | +| | `cappedSize` | | ⚠️ | | +| | `cappedMax` | | ⚠️ | | +| | `changeStreamPreAndPostImages` | | ⚠️ | | +| `compact` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/3466) | +| | `force` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `compactStructuredEncryptionData` | | | ❌ | | +| | `compactionTokens` | | ⚠️ | | +| `convertToCapped` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/3457) | +| | `size` | | ⚠️ | | +| | `writeConcern` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `create` | | | ✅ | | +| | `capped` | | ✅️ | | +| | `timeseries` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/177) | +| | | `timeField` | ⚠️ | | +| | | `metaField` | ⚠️ | | +| | | `granularity` | ⚠️ | | +| | `expireAfterSeconds` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2415) | +| | `clusteredIndex` | | ⚠️ | | +| | `changeStreamPreAndPostImages` | | ⚠️ | | +| | `autoIndexId` | | ⚠️ | Ignored | +| | `size` | | ✅️ | | +| | `max` | | ✅ | | +| | `storageEngine` | | ⚠️ | Ignored | +| | `validator` | | ⚠️ | Not implemented in PostgreSQL | +| | `validationLevel` | | ⚠️ | Unimplemented | +| | `validationAction` | | ⚠️ | Unimplemented | +| | `indexOptionDefaults` | | ⚠️ | Ignored | +| | `viewOn` | | ⚠️ | Unimplemented | +| | `pipeline` | | ⚠️ | Unimplemented | +| | `collation` | | ❌ | Unimplemented | +| | `writeConcern` | | ⚠️ | Ignored | +| | `encryptedFields` | | ⚠️ | | +| | `comment` | | ⚠️ | Ignored | +| `createIndexes` | | | ✅ | | +| | `indexes` | | ✅ | | +| | | `key` | ✅ | | +| | | `name` | ✅️ | | +| | | `unique` | ✅ | | +| | | `partialFilterExpression` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2448) | +| | | `sparse` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2448) | +| | | `expireAfterSeconds` | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2415) | +| | | `hidden` | ❌ | Unimplemented | +| | | `storageEngine` | ❌ | Unimplemented | +| | | `weights` | ❌ | Unimplemented | +| | | `default_language` | ❌ | Unimplemented | +| | | `language_override` | ❌ | Unimplemented | +| | | `textIndexVersion` | ❌ | Unimplemented | +| | | `2dsphereIndexVersion` | ❌ | Unimplemented | +| | | `bits` | ❌ | Unimplemented | +| | | `min` | ❌ | Unimplemented | +| | | `max` | ❌ | Unimplemented | +| | | `bucketSize` | ❌ | Unimplemented | +| | | `collation` | ❌ | Unimplemented | +| | | `wildcardProjection` | ❌ | Unimplemented | +| | `writeConcern` | | ⚠️ | | +| | `commitQuorum` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `currentOp` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/2399) | +| | `$ownOps` | | ⚠️ | | +| | `$all` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `drop` | | | ✅ | | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `dropDatabase` | | | ✅ | | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `dropConnections` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1511) | +| | `hostAndPort` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `dropIndexes` | | | ✅ | | +| | `index` | | ✅ | | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `filemd5` | | | ❌ | | +| `fsync` | | | ❌ | | +| `fsyncUnlock` | | | ❌ | | +| | `lock` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `getDefaultRWConcern` | | | ❌ | | +| | `inMemory` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `getClusterParameter` | | | ❌ | | +| `getParameter` | | | ❌ | | +| | `comment` | | ⚠️ | | +| `killCursors` | | | ✅ | | +| | `cursors` | | ✅ | | +| | `comment` | | ⚠️ | | +| `killOp` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1515) | +| | `op` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `listCollections` | | | ✅ | | +| | `filter` | | ✅ | | +| | `nameOnly` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/3624) | +| | `authorizedCollections` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/3770) | +| | `comment` | | ⚠️ | | +| `listDatabases` | | | ✅ | | +| | `filter` | | ✅ | | +| | `nameOnly` | | ✅ | | +| | `authorizedDatabases` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/3769) | +| | `comment` | | ⚠️ | Ignored | +| `listIndexes` | | | ✅ | | +| | `cursor.batchSize` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `logRotate` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1959) | +| | `` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `reIndex` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1516) | +| `renameCollection` | | | ✅ | | +| | `to` | | ✅ | [Issue](https://github.com/FerretDB/FerretDB/issues/2563) | +| | `dropTarget` | | ⚠️ | [Issue](https://github.com/FerretDB/FerretDB/issues/2565) | +| | `writeConcern` | | ⚠️ | Ignored | +| | `comment` | | ⚠️ | Ignored | +| `rotateCertificates` | | | ❌ | | +| `setFeatureCompatibilityVersion` | | | ❌ | | +| `setIndexCommitQuorum` | | | ❌ | | +| | `setIndexCommitQuorum` | | ⚠️ | | +| | `indexNames` | | ⚠️ | | +| | `commitQuorum` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `setParameter` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1518) | +| `setDefaultRWConcern` | | | ❌ | | +| | `defaultReadConcern` | | ⚠️ | | +| | `defaultWriteConcern` | | ⚠️ | | +| | `writeConcern` | | ⚠️ | | +| | `comment` | | ⚠️ | | +| `shutdown` | | | ❌ | [Issue](https://github.com/FerretDB/FerretDB/issues/1519) | +| | `force` | | ⚠️ | | +| | `timeoutSecs` | | ⚠️ | | +| | `comment` | | ⚠️ | | + +## Diagnostic commands + +| Command | Argument | Status | Comments | +| -------------------- | ---------------------- | ------ | -------------------------------- | +| `buildInfo` | | ✅ | Basic command is fully supported | +| `collStats` | | ✅ | Basic command is fully supported | +| | `collStats` | ✅ | | +| | `scale` | ✅ | | +| `connPoolStats` | | ❌ | Unimplemented | +| `connectionStatus` | | ✅ | Basic command is fully supported | +| | `showPrivileges` | ✅ | | +| `dataSize` | | ✅ | Basic command is fully supported | +| | `keyPattern` | ⚠️ | Unimplemented | +| | `min` | ⚠️ | Unimplemented | +| | `max` | ⚠️ | Unimplemented | +| | `estimate` | ⚠️ | Ignored | +| `dbHash` | | ❌ | Unimplemented | +| | `collection` | ⚠️ | | +| `dbStats` | | ✅ | Basic command is fully supported | +| | `scale` | ✅ | | +| | `freeStorage` | ⚠️ | Unimplemented | +| `driverOIDTest` | | ⚠️ | Unimplemented | +| `explain` | | ✅ | Basic command is fully supported | +| | `verbosity` | ⚠️ | Ignored | +| | `comment` | ⚠️ | Unimplemented | +| `features` | | ❌ | Unimplemented | +| `getCmdLineOpts` | | ✅ | Basic command is fully supported | +| `getLog` | | ✅ | Basic command is fully supported | +| `hostInfo` | | ✅ | Basic command is fully supported | +| `_isSelf` | | ❌ | Unimplemented | +| `listCommands` | | ✅ | Basic command is fully supported | +| `lockInfo` | | ❌ | Unimplemented | +| `netstat` | | ❌ | Unimplemented | +| `ping` | | ✅ | Basic command is fully supported | +| `profile` | | ❌ | Unimplemented | +| | `slowms` | ⚠️ | | +| | `sampleRate` | ⚠️ | | +| | `filter` | ⚠️ | | +| `serverStatus` | | ✅ | Basic command is fully supported | +| `shardConnPoolStats` | | ❌ | Unimplemented | +| `top` | | ❌ | Unimplemented | +| `validate` | | ✅ | Basic command is fully supported | +| | `full` | ⚠️ | | +| | `repair` | ⚠️ | | +| | `metadata` | ⚠️ | | +| | `checkBSONConformance` | ⚠️ | | +| `validateDBMetadata` | | ❌ | Unimplemented | +| | `apiParameters` | ⚠️ | | +| | `db` | ⚠️ | | +| | `collections` | ⚠️ | | +| `whatsmyuri` | | ✅ | Basic command is fully supported | diff --git a/website/versioned_docs/version-v1.16/security/_category_.yml b/website/versioned_docs/version-v1.16/security/_category_.yml new file mode 100644 index 000000000000..aa19bc8c4576 --- /dev/null +++ b/website/versioned_docs/version-v1.16/security/_category_.yml @@ -0,0 +1,7 @@ +--- +label: Security +position: 13 +link: + type: generated-index + slug: /security/ + description: Authentication and TLS diff --git a/website/versioned_docs/version-v1.16/security/authentication.md b/website/versioned_docs/version-v1.16/security/authentication.md new file mode 100644 index 000000000000..ddbfe79ab29c --- /dev/null +++ b/website/versioned_docs/version-v1.16/security/authentication.md @@ -0,0 +1,105 @@ +--- +sidebar_position: 1 +slug: /security/authentication/ # referenced in error messages +description: Learn to use authentication mechanisms +--- + +# Authentication + +FerretDB does not store authentication information (usernames and passwords) itself but uses the backend's authentication mechanisms. +The default username and password can be specified in FerretDB's connection string, +but the client could use a different user by providing a username and password in MongoDB URI. +For example, if the server was started with `postgres://user1:pass1@postgres:5432/ferretdb`, +anonymous clients will be authenticated as user1, +but clients that use `mongodb://user2:pass2@ferretdb:27018/ferretdb?tls=true&authMechanism=PLAIN` MongoDB URI will be authenticated as user2. +Since usernames and passwords are transferred in plain text, +the use of [TLS](../security/tls-connections.md) is highly recommended. + +## PostgreSQL backend with default username and password + +In following examples, default username and password are specified in FerretDB's connection string `user1:pass1`. +Ensure `user1` is a PostgreSQL user with necessary +[privileges](https://www.postgresql.org/docs/current/sql-grant.html). +See more about [creating PostgreSQL user](https://www.postgresql.org/docs/current/sql-createuser.html) +and [PostgreSQL authentication methods](https://www.postgresql.org/docs/current/auth-methods.html). + +### Using `ferretdb` package + +Start `ferretdb` by specifying `--postgresql-url` with default username and password. + +```sh +ferretdb --postgresql-url=postgres://user1:pass1@localhost:5432/ferretdb +``` + +An anonymous client is authenticated with default `user1` from `--postgresql-url`. + +```sh +mongosh 'mongodb://127.0.0.1/ferretdb' +``` + +A client that specify username and password in MongoDB URI as below is authenticated as `user2`. + +```sh +mongosh 'mongodb://user2:pass2@127.0.0.1/ferretdb?authMechanism=PLAIN' +``` + +### Using Docker + +For Docker, specify `FERRETDB_POSTGRESQL_URL` with default username and password. + +```yaml +services: + postgres: + image: postgres + environment: + - POSTGRES_USER=username + - POSTGRES_PASSWORD=password + - POSTGRES_DB=ferretdb + volumes: + - ./data:/var/lib/postgresql/data + + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27017:27017 + environment: + - FERRETDB_POSTGRESQL_URL=postgres://user1:pass1@postgres:5432/ferretdb + +networks: + default: + name: ferretdb +``` + +To start `ferretdb`, use docker compose. + +```sh +docker compose up +``` + +An anonymous client is authenticated with `user1` from `FERRETDB_POSTGRESQL_URL`. +Use following command to run `mongosh` inside the temporary MongoDB container, +attached to the same Docker network. + +```sh +docker run --rm -it --network=ferretdb --entrypoint=mongosh \ + mongo 'mongodb://ferretdb/ferretdb' +``` + +A client that specify username and password in MongoDB URI as below is authenticated as `user2`. + +```sh +docker run --rm -it --network=ferretdb --entrypoint=mongosh \ + mongo 'mongodb://user2:pass2@ferretdb/ferretdb?authMechanism=PLAIN' +``` + +## Authentication Handshake + +:::note +Some drivers may still use the legacy `hello` command to complete a handshake. +::: + +If you encounter any issues while authenticating with FerretDB, try setting the Stable API version to V1 on the client as this may prevent legacy commands from being used. +Please refer to your specific driver documentation on how to set this field. + +If this does not resolve your issue please file a bug report [here](https://github.com/FerretDB/FerretDB/issues/new?assignees=ferretdb-bot&labels=code%2Fbug%2Cnot+ready&projects=&template=bug.yml). diff --git a/website/versioned_docs/version-v1.16/security/tls-connections.md b/website/versioned_docs/version-v1.16/security/tls-connections.md new file mode 100644 index 000000000000..68901490a694 --- /dev/null +++ b/website/versioned_docs/version-v1.16/security/tls-connections.md @@ -0,0 +1,121 @@ +--- +sidebar_position: 2 +description: Learn to secure connections using TLS +--- + +# TLS Connections + +It is possible to encrypt connections between FerretDB and clients by using TLS. +All you need to do is to start the server with the following flags or environment variables: + +- `--listen-tls` / `FERRETDB_LISTEN_TLS` specifies the TCP hostname and port + that will be used for listening for incoming TLS connections. + If empty, TLS listener is disabled; +- `--listen-tls-cert-file` / `FERRETDB_LISTEN_TLS_CERT_FILE` specifies the PEM encoded, TLS certificate file + that will be presented to clients; +- `--listen-tls-key-file` / `FERRETDB_LISTEN_TLS_KEY_FILE` specifies the TLS private key file + that will be used to decrypt communications; +- `--listen-tls-ca-file` / `FERRETDB_LISTEN_TLS_CA_FILE` specifies the root CA certificate file + that will be used to verify client certificates. + +Then use `tls` query parameters in MongoDB URI for the client. +You may also need to set `tlsCAFile` parameter if the system-wide certificate authority did not issue the server's certificate. +See documentation for your client or driver for more details. +Example: `mongodb://ferretdb:27018/?tls=true&tlsCAFile=companyRootCA.pem`. + +## PostgreSQL backend with TLS + +Using TLS is recommended if username and password are transferred in plain text. + +In following examples, FerretDB uses TLS certificates to secure the connection. +Example certificates are found in [build/certs](https://github.com/FerretDB/FerretDB/tree/main/build/certs). +The `ferretdb` server uses TLS server certificate file, TLS private key file and root CA certificate file. + +```text +server-certs/ +├── rootCA-cert.pem +├── server-cert.pem +└── server-key.pem +``` + +The client uses TLS client certificate file and root CA certificate file. + +```text +client-certs/ +├── client.pem +└── rootCA-cert.pem +``` + +### Using TLS with `ferretdb` package + +The example below connects to localhost PostgreSQL instance using TLS with certificates in `server-certs` directory. +Be sure to check that `server-certs` directory and files are present. + +```sh +ferretdb \ + --postgresql-url=postgres://localhost:5432/ferretdb \ + --listen-tls=:27018 \ + --listen-tls-cert-file=./server-certs/server-cert.pem \ + --listen-tls-key-file=./server-certs/server-key.pem \ + --listen-tls-ca-file=./server-certs/rootCA-cert.pem +``` + +Using `mongosh`, a client connects to ferretdb as `user2` using TLS certificates in `client-certs` directory. +Be sure to check that `client-certs` directory and files are present. + +```sh +mongosh 'mongodb://user2:pass2@127.0.0.1:27018/ferretdb?authMechanism=PLAIN&tls=true&tlsCertificateKeyFile=./client-certs/client.pem&tlsCaFile=./client-certs/rootCA-cert.pem' +``` + +### Using TLS with Docker + +For using Docker to run `ferretdb` server, `docker-compose.yml` example for TLS is provided in below. +The Docker host requires certificates `server-certs` directory, +and volume is mounted from `./server-certs` of Docker host to `/etc/certs` of Docker container. + +```yaml +services: + postgres: + image: postgres + environment: + - POSTGRES_USER=username + - POSTGRES_PASSWORD=password + - POSTGRES_DB=ferretdb + volumes: + - ./data:/var/lib/postgresql/data + + ferretdb: + image: ghcr.io/ferretdb/ferretdb + restart: on-failure + ports: + - 27018:27018 + environment: + - FERRETDB_POSTGRESQL_URL=postgres://postgres:5432/ferretdb + - FERRETDB_LISTEN_TLS=:27018 + - FERRETDB_LISTEN_TLS_CERT_FILE=/etc/certs/server-cert.pem + - FERRETDB_LISTEN_TLS_KEY_FILE=/etc/certs/server-key.pem + - FERRETDB_LISTEN_TLS_CA_FILE=/etc/certs/rootCA-cert.pem + volumes: + - ./server-certs:/etc/certs + +networks: + default: + name: ferretdb +``` + +To start `ferretdb`, use docker compose. + +```sh +docker compose up +``` + +In the following example, a client connects to MongoDB URI using TLS certificates as `user2`. +It uses Docker volume to mount `./clients-certs` of Docker host to `/clients` Docker container. + +```sh +docker run --rm -it \ + --network=ferretdb \ + --volume ./client-certs:/clients \ + --entrypoint=mongosh \ + mongo 'mongodb://user2:pass2@host.docker.internal:27018/ferretdb?authMechanism=PLAIN&tls=true&tlsCertificateKeyFile=/clients/client.pem&tlsCaFile=/clients/rootCA-cert.pem' +``` diff --git a/website/versioned_docs/version-v1.16/telemetry.md b/website/versioned_docs/version-v1.16/telemetry.md new file mode 100644 index 000000000000..281fcb991ee7 --- /dev/null +++ b/website/versioned_docs/version-v1.16/telemetry.md @@ -0,0 +1,153 @@ +--- +sidebar_position: 12 +slug: /telemetry/ # referenced in many places; must not change +--- + +# Telemetry reporting + +FerretDB collects basic anonymous usage data and sends them to our telemetry service ([FerretDB Beacon](https://beacon.ferretdb.io)), +which helps us understand its usage, and how we can further increase compatibility and enhance our product. +It also enables us to provide you information about available updates. + +Your privacy is important to us, and we understand how sensitive data collection can be, +which is why we are not collecting any personally-identifying information +or share any of the data with third parties. + +The following data is collected: + +- FerretDB version +- Random instance UUID +- [Autonomous system]() number, + cloud provider region, or country derived from IP address (but the IP address itself) +- Uptime +- Backend (PostgreSQL or SQLite) version +- Installation type (Docker, package, cloud provider marketplace, self-built) +- Build configuration (Go version, build flags and tags) +- Command statistics: + - protocol operation codes (e.g. `OP_MSG`, `OP_QUERY`); + - command names (e.g. `find`, `aggregate`); + - arguments (e.g. `sort`, `$count (stage)`); + - error codes (e.g. `NotImplemented`, `InternalError`; or `ok`). + +:::info +Argument values, data field names, successful responses, or error messages are never collected. +::: + +## Version notification + +When a FerretDB update is available, +the telemetry service sends periodic notifications containing information about the latest FerretDB version. +This information is logged in the server logs and `startupWarnings` command output. + +While you may not upgrade to the latest release immediately, +ensure that you update early to take advantage of recent bug fixes, new features, and performance improvements. + +## Configure telemetry + +The telemetry reporter has three state settings: `enabled`, `disabled`, and `undecided` (default). +The latter acts as if it is `enabled` with two differences: + +- When `enabled`, the first report is sent right after FerretDB starts. + If `undecided`, the first report is delayed by one hour. + That should give you enough time to disable it if you decide to do so. +- Similarly, when `enabled`, the last report is sent right before FerretDB shuts down. + That does not happen when `undecided`. + +:::info +`undecided` state does not automatically change into `enabled` or `disabled` after the first or any other report. +Explicit user action is required (see below) to change an `undecided` state to `enabled` or `disabled`. +::: + +Telemetry reporting is always disabled for [embedded FerretDB](https://pkg.go.dev/github.com/FerretDB/FerretDB/ferretdb) +and can't be configured. + +:::info +Despite the autogenerated message by `mongosh` regarding MongoDB's free cloud-based monitoring service, please note that no data will ever be shared with MongoDB Inc. +::: + +### Disable telemetry + +We urge you not to disable telemetry reporter, as its insights will help us enhance our software. + +While we are grateful for these usage insights, we understand that not everyone is comfortable with sending them. + +:::caution +If you disable telemetry, automated version checks and information on updates will not be available. +::: + +Telemetry can be disabled using any of the following options: + +1. Pass the command-line flag `--telemetry` to the FerretDB executable with value: + `0`, `f`, `false`, `n`, `no`, `off`, `disable`, `disabled`, `optout`, `opt-out`, `disallow`, `forbid`. + + ```sh + --telemetry=disable + ``` + +2. Set the environment variable `FERRETDB_TELEMETRY`. + + ```sh + export FERRETDB_TELEMETRY=disable + ``` + +3. Set the `DO_NOT_TRACK` environment variable with any of the following values: + `1`, `t`, `true`, `y`, `yes`, `on`, `enable`, `enabled`. + + ```sh + export DO_NOT_TRACK=true + ``` + +4. Rename FerretDB executable to include a `donottrack` string. + + :::caution + If telemetry is disabled using this option, you cannot use the `--telemetry` flag or environment variables + until the `donottrack` string is removed. + ::: + +5. Use the `db.disableFreeMonitoring()` command on runtime. + + ```js + db.disableFreeMonitoring() + ``` + + :::caution + If the telemetry is set via a command-line flag, an environment variable or a filename, it's not possible + to modify its state via command. + ::: + +### Enable telemetry + +Telemetry can be explicitly enabled (see [above](#configure-telemetry)) with the command-line flag `--telemetry` +by setting one of the values: +`1`, `t`, `true`, `y`, `yes`, `on`, `enable`, `enabled`, `optin`, `opt-in`, `allow`. + +```sh +--telemetry=enable +``` + +You can also use `FERRETDB_TELEMETRY` environment variable with same values +or on runtime via `db.enableFreeMonitoring()` command. + +```sh +export FERRETDB_TELEMETRY=enable +``` + +```js +db.enableFreeMonitoring() +``` + +One case when explicitly enabling telemetry is useful is if you want to help us improve compatibility +with your application by running its integration tests or just by testing it manually. +If you leave the telemetry state undecided and your test lasts less than an hour, +we will not have data about unimplemented commands and errors. + +If you want to help us with that, please do the following: + +1. Start FerretDB with [debug logging](configuration/flags.md) and telemetry explicitly enabled. + Confirm that telemetry is enabled from the logs. +2. Test your application with integration tests or manually. +3. Gracefully stop FerretDB with `SIGTERM` or `docker stop` (not with `SIGKILL` or `docker kill`). +4. Optionally, locate instance UUID in the `state.json` file in the state directory + (`/state` for Docker, current directory otherwise) and send it to us. + That would allow us to locate your data and understand what FerretDB functionality + should be implemented or fixed to improve compatibility with your application. diff --git a/website/versioned_docs/version-v1.16/understanding-ferretdb.md b/website/versioned_docs/version-v1.16/understanding-ferretdb.md new file mode 100644 index 000000000000..c866497ea45e --- /dev/null +++ b/website/versioned_docs/version-v1.16/understanding-ferretdb.md @@ -0,0 +1,197 @@ +--- +sidebar_position: 2 +--- + +# Understanding FerretDB + +FerretDB is an open-source proxy that translates MongoDB wire protocol queries to SQL, +with PostgreSQL or SQLite as the database engine. +It uses the same commands, drivers, and tools as MongoDB. + +```mermaid +flowchart LR + A["Any application\nAny MongoDB driver"] + F{{FerretDB}} + P[(PostgreSQL)] + S[("SQLite")] + + A -- "MongoDB protocol\nBSON" --> F + F -- "PostgreSQL protocol\nSQL" --> P + F -. "SQLite library\nSQL" .-> S +``` + +:::tip +New to FerretDB? + +Check out our: + +- [Installation guide](quickstart-guide/docker.md) +- [Key differences](diff.md) +- [Basic CRUD operations](basic-operations/index.md) + +::: + +## Supported backends + +:::caution +FerretDB is under constant development. +As with any database, before moving to production, please verify if it is suitable for your application. +::: + +### PostgreSQL + +PostgreSQL backend is our main backend and is fully supported. + +PostgreSQL should be configured with `UTF8` encoding and one of the following locales: +`POSIX`, `C`, `C.UTF8`, `en_US.UTF8`. + +MongoDB databases are mapped to PostgreSQL schemas in a single PostgreSQL database that should be created in advance. +MongoDB collections are mapped to PostgreSQL tables. +MongoDB documents are mapped to rows with a single [JSONB](https://www.postgresql.org/docs/current/datatype-json.html) column. +Those mappings will change as we work on improving compatibility and performance, +but no breaking changes will be introduced without a major version bump. + +### SQLite + +We also support the [SQLite](https://www.sqlite.org/) backend. + +MongoDB databases are mapped to SQLite database files. +MongoDB collections are mapped to SQLite tables. +MongoDB documents are mapped to rows with a single [JSON1](https://www.sqlite.org/json1.html) column. +Those mappings will change as we work on improving compatibility and performance, +but no breaking changes will be introduced without a major version bump. + +### SAP HANA (alpha) + +Currently, [we are also working](https://blogs.sap.com/2022/12/13/introduction-to-sap-hana-compatibility-layer-for-mongodb-wire-protocol/) +with SAP on HANA compatibility. +It is not officially supported yet. + +## Documents + +Documents are self-describing records containing both data types and a description of the data being stored. +They are similar to rows in relational databases. +Here is an example of a single document: + +```js +{ + first: "Thomas", + last: "Edison", + invention: "Lightbulb", + birth: 1847 +} +``` + +The above data is stored in a single document. + +:::note +FerretDB follows almost the same naming conventions as MongoDB. +However, there are a few restrictions, which you can find [here](diff.md). +::: + +For complex documents, you can nest objects (subdocuments) inside a document. + +```js +{ + name: { + first: "Thomas", + last: "Edison" + }, + invention: "Lightbulb", + birth: 1847 +} +``` + +In the example above, the `name` field is a subdocument embedded into a document. + +## Dot notation + +Dot notations `(.)` are used to reference a field in an embedded document or its index position in an array. + +### Arrays + +Dot notations can be used to specify or query an array by concatenating a dot `(.)` with the index position of the field. + +```js +'array_name.index' +``` + +:::note +When using dot notations, the field name of the array and the specified value must be enclosed in quotation marks. +::: + +For example, let's take the following array field in a document: + +```js +animals: ['dog', 'cat', 'fish', 'fox'] +``` + +To reference the fourth field in the array, use the dot notation `"animals.3"`. + +Here are more examples of dot notations on arrays: + +- [Query an array](basic-operations/read.md#retrieve-documents-containing-a-specific-value-in-an-array) +- [Update an array](basic-operations/update.md#update-an-array-element) + +### Embedded documents + +To reference or query a field in an embedded document, concatenate the name of the embedded document and the field name using the dot notation. + +```js +'embedded_document_name.field' +``` + +Take the following document, for example: + +```js +{ + name:{ + first: "Tom", + last: "Barry" + }, + contact:{ + address:{ + city: "Kent", + state: "Ohio" + }, + phone: "432-124-1234" + } +} +``` + +To reference the `city` field in the embedded document, use the dot notation `"contact.address.city"`. + +For dot notation examples on embedded documents, see here: + +- [Query an embedded document](basic-operations/read.md#query-on-an-embedded-or-nested-document) +- [Update an embedded document](basic-operations/update.md#update-an-embedded-document) + +## Collections + +Collections are a repository for documents. +To some extent, they are similar to tables in a relational database. +If a collection does not exist, FerretDB creates a new one when you insert documents for the first time. +A collection may contain one or more documents. +For example, the following collection contains three documents. + +```js +{ + Scientists: [ + { + first: 'Alan', + last: 'Turing', + born: 1912 + }, + { + first: 'Thomas', + last: 'Edison', + birth: 1847 + }, + { + first: 'Nikola', + last: 'Tesla', + birth: 1856 + } + ] +} +``` diff --git a/website/versioned_sidebars/version-v1.14-sidebars.json b/website/versioned_sidebars/version-v1.14-sidebars.json new file mode 100644 index 000000000000..2782dc0f445a --- /dev/null +++ b/website/versioned_sidebars/version-v1.14-sidebars.json @@ -0,0 +1,8 @@ +{ + "sidebar": [ + { + "type": "autogenerated", + "dirName": "." + } + ] +} diff --git a/website/versioned_sidebars/version-v1.15-sidebars.json b/website/versioned_sidebars/version-v1.15-sidebars.json new file mode 100644 index 000000000000..2782dc0f445a --- /dev/null +++ b/website/versioned_sidebars/version-v1.15-sidebars.json @@ -0,0 +1,8 @@ +{ + "sidebar": [ + { + "type": "autogenerated", + "dirName": "." + } + ] +} diff --git a/website/versioned_sidebars/version-v1.16-sidebars.json b/website/versioned_sidebars/version-v1.16-sidebars.json new file mode 100644 index 000000000000..2782dc0f445a --- /dev/null +++ b/website/versioned_sidebars/version-v1.16-sidebars.json @@ -0,0 +1,8 @@ +{ + "sidebar": [ + { + "type": "autogenerated", + "dirName": "." + } + ] +} diff --git a/website/versions.json b/website/versions.json index 0d4f101c7a37..1f0a34254ca7 100644 --- a/website/versions.json +++ b/website/versions.json @@ -1,2 +1,5 @@ [ + "v1.16", + "v1.15", + "v1.14" ]