Skip to content

Commit f4041ce

Browse files
authored
fix(db-mongodb): joins with singular collection name (#8933)
### What? Properly specifies `$lookup.from` when the collection name is singular. ### Why? MongoDB can pluralize the collection name and so can be different for singular ones. ### How? Uses the collection name from the driver directly `adapter.collections[slug].collection.name` instead of just `slug`.
1 parent 1231251 commit f4041ce

File tree

6 files changed

+62
-3
lines changed

6 files changed

+62
-3
lines changed

packages/db-mongodb/src/utilities/buildJoinAggregation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export const buildJoinAggregation = async ({
106106
$lookup: {
107107
as: `${as}.docs`,
108108
foreignField: `${join.field.on}${code}`,
109-
from: slug,
109+
from: adapter.collections[slug].collection.name,
110110
localField: versions ? 'parent' : '_id',
111111
pipeline,
112112
},
@@ -147,7 +147,7 @@ export const buildJoinAggregation = async ({
147147
$lookup: {
148148
as: `${as}.docs`,
149149
foreignField: `${join.field.on}${localeSuffix}`,
150-
from: slug,
150+
from: adapter.collections[slug].collection.name,
151151
localField: versions ? 'parent' : '_id',
152152
pipeline,
153153
},

test/joins/collections/Categories.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { CollectionConfig } from 'payload'
22

33
import { categoriesSlug, postsSlug } from '../shared.js'
4+
import { singularSlug } from './Singular.js'
45

56
export const Categories: CollectionConfig = {
67
slug: categoriesSlug,
@@ -83,5 +84,11 @@ export const Categories: CollectionConfig = {
8384
},
8485
],
8586
},
87+
{
88+
name: 'singulars',
89+
type: 'join',
90+
collection: singularSlug,
91+
on: 'category',
92+
},
8693
],
8794
}

test/joins/collections/Singular.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { CollectionConfig } from 'payload'
2+
3+
export const singularSlug = 'singular'
4+
5+
export const Singular: CollectionConfig = {
6+
slug: singularSlug,
7+
fields: [
8+
{
9+
type: 'relationship',
10+
relationTo: 'categories',
11+
name: 'category',
12+
},
13+
],
14+
}

test/joins/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
55
import { Categories } from './collections/Categories.js'
66
import { CategoriesVersions } from './collections/CategoriesVersions.js'
77
import { Posts } from './collections/Posts.js'
8+
import { Singular } from './collections/Singular.js'
89
import { Uploads } from './collections/Uploads.js'
910
import { Versions } from './collections/Versions.js'
1011
import { seed } from './seed.js'
@@ -20,6 +21,7 @@ export default buildConfigWithDefaults({
2021
Uploads,
2122
Versions,
2223
CategoriesVersions,
24+
Singular,
2325
{
2426
slug: localizedPostsSlug,
2527
admin: {

test/joins/int.spec.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getFileByPath } from 'payload'
55
import { fileURLToPath } from 'url'
66

77
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
8-
import type { Category, Config, Post } from './payload-types.js'
8+
import type { Category, Config, Post, Singular } from './payload-types.js'
99

1010
import { devUser } from '../credentials.js'
1111
import { idToString } from '../helpers/idToString.js'
@@ -642,6 +642,8 @@ describe('Joins Field', () => {
642642
}
643643
}
644644
}`
645+
646+
expect(true).toBeTruthy()
645647
const response = await restClient
646648
.GRAPHQL_POST({ body: JSON.stringify({ query }) })
647649
.then((res) => res.json())
@@ -666,6 +668,21 @@ describe('Joins Field', () => {
666668

667669
expect(allCategories.totalDocs).toBe(allCategoriesByIds.totalDocs)
668670
})
671+
672+
it('should join with singular collection name', async () => {
673+
const {
674+
docs: [category],
675+
} = await payload.find({ collection: 'categories', limit: 1, depth: 0 })
676+
677+
const singular = await payload.create({
678+
collection: 'singular',
679+
data: { category: category.id },
680+
})
681+
682+
const categoryWithJoins = await payload.findByID({ collection: 'categories', id: category.id })
683+
684+
expect((categoryWithJoins.singulars.docs[0] as Singular).id).toBe(singular.id)
685+
})
669686
})
670687

671688
async function createPost(overrides?: Partial<Post>, locale?: Config['locale']) {

test/joins/payload-types.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface Config {
1616
uploads: Upload;
1717
versions: Version;
1818
'categories-versions': CategoriesVersion;
19+
singular: Singular;
1920
'localized-posts': LocalizedPost;
2021
'localized-categories': LocalizedCategory;
2122
users: User;
@@ -133,6 +134,20 @@ export interface Category {
133134
hasNextPage?: boolean | null;
134135
} | null;
135136
};
137+
singulars?: {
138+
docs?: (string | Singular)[] | null;
139+
hasNextPage?: boolean | null;
140+
} | null;
141+
updatedAt: string;
142+
createdAt: string;
143+
}
144+
/**
145+
* This interface was referenced by `Config`'s JSON-Schema
146+
* via the `definition` "singular".
147+
*/
148+
export interface Singular {
149+
id: string;
150+
category?: (string | null) | Category;
136151
updatedAt: string;
137152
createdAt: string;
138153
}
@@ -231,6 +246,10 @@ export interface PayloadLockedDocument {
231246
relationTo: 'categories-versions';
232247
value: string | CategoriesVersion;
233248
} | null)
249+
| ({
250+
relationTo: 'singular';
251+
value: string | Singular;
252+
} | null)
234253
| ({
235254
relationTo: 'localized-posts';
236255
value: string | LocalizedPost;

0 commit comments

Comments
 (0)