From ad097820bfe32b0a4ef428a37a78e5a569258ec6 Mon Sep 17 00:00:00 2001 From: Dan Ribbens Date: Thu, 30 Sep 2021 16:05:47 -0400 Subject: [PATCH] feat: add indexSortableField option to create indexes for sortable fields on all collections --- demo/payload.config.ts | 1 + docs/configuration/overview.mdx | 1 + docs/production/deployment.mdx | 2 ++ src/config/schema.ts | 1 + src/config/types.ts | 3 ++- src/globals/buildModel.ts | 2 +- src/mongoose/buildSchema.ts | 7 +++++++ 7 files changed, 15 insertions(+), 2 deletions(-) diff --git a/demo/payload.config.ts b/demo/payload.config.ts index 834c59ef759..adaadd1cb2b 100644 --- a/demo/payload.config.ts +++ b/demo/payload.config.ts @@ -130,6 +130,7 @@ export default buildConfig({ defaultLocale: 'en', fallback: true, }, + // indexSortableFields: true, hooks: { afterError: (err) => { console.error('global error config handler', err); diff --git a/docs/configuration/overview.mdx b/docs/configuration/overview.mdx index c18434afa57..b425608b07c 100644 --- a/docs/configuration/overview.mdx +++ b/docs/configuration/overview.mdx @@ -29,6 +29,7 @@ Payload is a *config-based*, code-first CMS and application framework. The Paylo | `csrf` | A whitelist array of URLs to allow Payload cookies to be accepted from as a form of CSRF protection. [More](/docs/authentication/overview#csrf-protection) | | `defaultDepth` | If a user does not specify `depth` while requesting a resource, this depth will be used. [More](/docs/getting-started/concepts#depth) | | `maxDepth` | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. | +| `indexSortableFields`| Automatically create database an index on every sortable type of top-level field. | | `upload` | Base Payload upload configuration. [More](/docs/upload/overview#payload-wide-upload-options). | | `routes` | Control the routing structure that Payload binds itself to. Specify `admin`, `api`, `graphQL`, and `graphQLPlayground`. | | `email` | Base email settings to allow Payload to generate email such as Forgot Password requests and other requirements. [More](/docs/email/overview#configuration) | diff --git a/docs/production/deployment.mdx b/docs/production/deployment.mdx index 3d7eb6f1217..f3466579efd 100644 --- a/docs/production/deployment.mdx +++ b/docs/production/deployment.mdx @@ -72,6 +72,8 @@ If you are using a [persistent filesystem-based cloud host](#persistent-vs-ephem Alternatively, you can rely on a third-party MongoDB host such as [MongoDB Atlas](https://www.mongodb.com/). With Atlas or a similar cloud provider, you can trust them to take care of your database's availability, security, redundancy, and backups. +When using Azure Cosmos, MongoDB requires an index on any field being sorted on in a query. To make this easier, see the [indexSortableFields](/docs/configuration/overview) configuration option. + ## File storage If you are using Payload to [manage file uploads](/docs/upload/overview), you need to consider where your uploaded files will be permanently stored. If you do not use Payload for file uploads, then this section does not impact your app whatsoever. diff --git a/src/config/schema.ts b/src/config/schema.ts index 8a2865bc3b4..8c802a54184 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -80,6 +80,7 @@ export default joi.object({ }), local: joi.boolean(), upload: joi.object(), + indexSortableFields: joi.boolean(), rateLimit: joi.object() .keys({ window: joi.number(), diff --git a/src/config/types.ts b/src/config/types.ts index cb719b4de23..5f7c7c6f5f1 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -120,6 +120,7 @@ export type Config = { }, defaultDepth?: number; maxDepth?: number; + indexSortableFields?: boolean; rateLimit?: { window?: number; max?: number; @@ -143,7 +144,7 @@ export type Config = { hooks?: { afterError?: AfterErrorHook; }; - plugins?: Plugin[] + plugins?: Plugin[]; }; export type SanitizedConfig = Omit, 'collections' | 'globals'> & { diff --git a/src/globals/buildModel.ts b/src/globals/buildModel.ts index c30416686a8..6ff6fceef33 100644 --- a/src/globals/buildModel.ts +++ b/src/globals/buildModel.ts @@ -9,7 +9,7 @@ const buildModel = (config: SanitizedConfig): mongoose.PaginateModel | null const Globals = mongoose.model('globals', globalsSchema); Object.values(config.globals).forEach((globalConfig) => { - const globalSchema = buildSchema(config, globalConfig.fields, {}); + const globalSchema = buildSchema(config, globalConfig.fields, { global: true }); Globals.discriminator(globalConfig.slug, globalSchema); }); diff --git a/src/mongoose/buildSchema.ts b/src/mongoose/buildSchema.ts index 902772898e7..1fbd6e3a35c 100644 --- a/src/mongoose/buildSchema.ts +++ b/src/mongoose/buildSchema.ts @@ -2,11 +2,13 @@ import { Schema, SchemaDefinition, SchemaOptions } from 'mongoose'; import { SanitizedConfig } from '../config/types'; import { ArrayField, Block, BlockField, Field, GroupField, RadioField, RelationshipField, RowField, SelectField, UploadField } from '../fields/config/types'; +import sortableFieldTypes from '../fields/sortableFieldTypes'; type BuildSchemaOptions = { options?: SchemaOptions allowIDField?: boolean disableRequired?: boolean + global?: boolean } type FieldSchemaGenerator = (field: Field, fields: SchemaDefinition, config: SanitizedConfig, buildSchemaOptions: BuildSchemaOptions) => SchemaDefinition; @@ -89,10 +91,15 @@ const buildSchema = (config: SanitizedConfig, configFields: Field[], buildSchema if (fieldSchema) { fields = fieldSchema(field, fields, config, buildSchemaOptions); } + // geospatial field index must be created after the schema is created if (fieldIndexMap[field.type]) { indexFields.push(...fieldIndexMap[field.type](field, config)); } + + if (config.indexSortableFields && !buildSchemaOptions.global && !field.index && !field.hidden && sortableFieldTypes.indexOf(field.type) > -1) { + indexFields.push({ [field.name]: 1 }); + } }); const schema = new Schema(fields, options);