Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions docs/database/mongodb.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,38 @@ We export compatibility options for [DocumentDB](https://aws.amazon.com/document

- Azure Cosmos DB does not support transactions that update two or more documents in different collections, which is a common case when using Payload (via hooks).
- Azure Cosmos DB requires the root config property `indexSortableFields` to be set to `true`.

## Using collation

There are situations where you may want to use language-specific string comparison, for example when sorting strings with accents or in different languages. MongoDB supports this via [collation](https://www.mongodb.com/docs/manual/reference/collation/).

We thread your locale automatically through to the MongoDB queries when collation is enabled in the adapter, so that when you sort by a field, it uses the correct language rules for that locale.

To enable collation, set the `collation` option in the adapter configuration:

```ts
import { mongooseAdapter } from '@payloadcms/db-mongodb'

export default buildConfig({
// Your config goes here
collections: [
// Collections go here
],
// Configure the Mongoose adapter here
db: mongooseAdapter({
// Mongoose-specific arguments go here.
// URL is required.
url: process.env.DATABASE_URI,
collation: {
// Set any MongoDB collation options here.
// The locale will be set automatically based on the request locale.
strength: 1, // Example option
},
}),
})
```

<Banner type="warning">
Collation will affect things like sort based on the locale being used. Please
test thoroughly before using in production as it can affect your queries.
</Banner>
3 changes: 3 additions & 0 deletions packages/db-mongodb/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export interface Args {
* @default false
*/
useAlternativeDropDatabase?: boolean

/**
* Set to `true` to use `BigInt` for custom ID fields of type `'number'`.
* Useful for databases that don't support `double` or `int32` IDs.
Expand Down Expand Up @@ -239,6 +240,7 @@ export function mongooseAdapter({
allowAdditionalKeys = false,
allowIDOnCreate = false,
autoPluralization = true,
collation,
collectionsSchemaOptions = {},
connectOptions,
disableFallbackSort = false,
Expand All @@ -263,6 +265,7 @@ export function mongooseAdapter({

// Mongoose-specific
autoPluralization,
collation,
collections: {},
// @ts-expect-error initialize without a connection
connection: undefined,
Expand Down
2 changes: 1 addition & 1 deletion test/database/getConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,7 @@ export const getConfig: () => Partial<Config> = () => ({
],
localization: {
defaultLocale: 'en',
locales: ['en', 'es'],
locales: ['en', 'es', 'uk'],
},
onInit: async (payload) => {
if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') {
Expand Down
48 changes: 48 additions & 0 deletions test/database/int.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5250,4 +5250,52 @@ describe('database', () => {
expect(typeof res?.val?.[0]).toBe('object')
expect(JSON.parse(JSON.stringify(res)).val[0]).toEqual('68378b649ca45274fb10126f')
})

itMongo('ensure mongodb respects collation when using collection in the config', async () => {
// Clear any existing documents
await payload.delete({ collection: 'simple', where: {} })

const expectedUnsortedItems = ['Євген', 'Віктор', 'Роман']
const expectedSortedItems = ['Віктор', 'Євген', 'Роман']

const simple_1 = await payload.create({
collection: 'simple',
locale: 'uk',
data: { text: 'Роман' },
})
const simple_2 = await payload.create({
collection: 'simple',
locale: 'uk',
data: { text: 'Віктор' },
})
const simple_3 = await payload.create({
collection: 'simple',
locale: 'uk',
data: { text: 'Євген' },
})

const results = await payload.find({
collection: 'simple',
locale: 'uk',
sort: 'text',
})

const initialMappedResults = results.docs.map((doc) => doc.text)

expect(initialMappedResults).toEqual(expectedUnsortedItems)

payload.db.collation = { strength: 1 }

const resultsWithCollation = await payload.find({
collection: 'simple',
locale: 'uk',
sort: 'text',
})

const collatedMappedResults = resultsWithCollation.docs.map((doc) => doc.text)

console.log({ docs: JSON.stringify(collatedMappedResults) })

expect(collatedMappedResults).toEqual(expectedSortedItems)
})
})
31 changes: 30 additions & 1 deletion test/database/payload-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export interface Config {
aliases: Alias;
'blocks-docs': BlocksDoc;
'unique-fields': UniqueField;
'payload-kv': PayloadKv;
users: User;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
Expand Down Expand Up @@ -116,6 +117,7 @@ export interface Config {
aliases: AliasesSelect<false> | AliasesSelect<true>;
'blocks-docs': BlocksDocsSelect<false> | BlocksDocsSelect<true>;
'unique-fields': UniqueFieldsSelect<false> | UniqueFieldsSelect<true>;
'payload-kv': PayloadKvSelect<false> | PayloadKvSelect<true>;
users: UsersSelect<false> | UsersSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
Expand All @@ -138,7 +140,7 @@ export interface Config {
'global-3': Global3Select<false> | Global3Select<true>;
'virtual-relation-global': VirtualRelationGlobalSelect<false> | VirtualRelationGlobalSelect<true>;
};
locale: 'en' | 'es';
locale: 'en' | 'es' | 'uk';
user: User & {
collection: 'users';
};
Expand Down Expand Up @@ -260,6 +262,7 @@ export interface Post {
localized?: string | null;
text?: string | null;
number?: number | null;
numberDefault?: number | null;
blocks?:
| {
nested?:
Expand Down Expand Up @@ -676,6 +679,23 @@ export interface UniqueField {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-kv".
*/
export interface PayloadKv {
id: string;
key: string;
data:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
Expand Down Expand Up @@ -904,6 +924,7 @@ export interface PostsSelect<T extends boolean = true> {
localized?: T;
text?: T;
number?: T;
numberDefault?: T;
blocks?:
| T
| {
Expand Down Expand Up @@ -1278,6 +1299,14 @@ export interface UniqueFieldsSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-kv_select".
*/
export interface PayloadKvSelect<T extends boolean = true> {
key?: T;
data?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users_select".
Expand Down
3 changes: 0 additions & 3 deletions test/generateDatabaseAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ const mongooseAdapterArgs = `
process.env.MONGODB_MEMORY_SERVER_URI ||
process.env.DATABASE_URI ||
'mongodb://127.0.0.1/payloadtests',
collation: {
strength: 1,
},
`

export const allDatabaseAdapters = {
Expand Down
Loading