diff --git a/demo/payload.config.ts b/demo/payload.config.ts index 834c59ef75..adaadd1cb2 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 c18434afa5..b425608b07 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 3d7eb6f121..f3466579ef 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 8a2865bc3b..8c802a5418 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 cb719b4de2..5f7c7c6f5f 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 c30416686a..6ff6fceef3 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 902772898e..1fbd6e3a35 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);