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`.
This commit is contained in:
@@ -106,7 +106,7 @@ export const buildJoinAggregation = async ({
|
|||||||
$lookup: {
|
$lookup: {
|
||||||
as: `${as}.docs`,
|
as: `${as}.docs`,
|
||||||
foreignField: `${join.field.on}${code}`,
|
foreignField: `${join.field.on}${code}`,
|
||||||
from: slug,
|
from: adapter.collections[slug].collection.name,
|
||||||
localField: versions ? 'parent' : '_id',
|
localField: versions ? 'parent' : '_id',
|
||||||
pipeline,
|
pipeline,
|
||||||
},
|
},
|
||||||
@@ -147,7 +147,7 @@ export const buildJoinAggregation = async ({
|
|||||||
$lookup: {
|
$lookup: {
|
||||||
as: `${as}.docs`,
|
as: `${as}.docs`,
|
||||||
foreignField: `${join.field.on}${localeSuffix}`,
|
foreignField: `${join.field.on}${localeSuffix}`,
|
||||||
from: slug,
|
from: adapter.collections[slug].collection.name,
|
||||||
localField: versions ? 'parent' : '_id',
|
localField: versions ? 'parent' : '_id',
|
||||||
pipeline,
|
pipeline,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { CollectionConfig } from 'payload'
|
import type { CollectionConfig } from 'payload'
|
||||||
|
|
||||||
import { categoriesSlug, postsSlug } from '../shared.js'
|
import { categoriesSlug, postsSlug } from '../shared.js'
|
||||||
|
import { singularSlug } from './Singular.js'
|
||||||
|
|
||||||
export const Categories: CollectionConfig = {
|
export const Categories: CollectionConfig = {
|
||||||
slug: categoriesSlug,
|
slug: categoriesSlug,
|
||||||
@@ -83,5 +84,11 @@ export const Categories: CollectionConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'singulars',
|
||||||
|
type: 'join',
|
||||||
|
collection: singularSlug,
|
||||||
|
on: 'category',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
14
test/joins/collections/Singular.ts
Normal file
14
test/joins/collections/Singular.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import type { CollectionConfig } from 'payload'
|
||||||
|
|
||||||
|
export const singularSlug = 'singular'
|
||||||
|
|
||||||
|
export const Singular: CollectionConfig = {
|
||||||
|
slug: singularSlug,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'relationship',
|
||||||
|
relationTo: 'categories',
|
||||||
|
name: 'category',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
|||||||
import { Categories } from './collections/Categories.js'
|
import { Categories } from './collections/Categories.js'
|
||||||
import { CategoriesVersions } from './collections/CategoriesVersions.js'
|
import { CategoriesVersions } from './collections/CategoriesVersions.js'
|
||||||
import { Posts } from './collections/Posts.js'
|
import { Posts } from './collections/Posts.js'
|
||||||
|
import { Singular } from './collections/Singular.js'
|
||||||
import { Uploads } from './collections/Uploads.js'
|
import { Uploads } from './collections/Uploads.js'
|
||||||
import { Versions } from './collections/Versions.js'
|
import { Versions } from './collections/Versions.js'
|
||||||
import { seed } from './seed.js'
|
import { seed } from './seed.js'
|
||||||
@@ -20,6 +21,7 @@ export default buildConfigWithDefaults({
|
|||||||
Uploads,
|
Uploads,
|
||||||
Versions,
|
Versions,
|
||||||
CategoriesVersions,
|
CategoriesVersions,
|
||||||
|
Singular,
|
||||||
{
|
{
|
||||||
slug: localizedPostsSlug,
|
slug: localizedPostsSlug,
|
||||||
admin: {
|
admin: {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { getFileByPath } from 'payload'
|
|||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
|
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
|
||||||
import type { Category, Config, Post } from './payload-types.js'
|
import type { Category, Config, Post, Singular } from './payload-types.js'
|
||||||
|
|
||||||
import { devUser } from '../credentials.js'
|
import { devUser } from '../credentials.js'
|
||||||
import { idToString } from '../helpers/idToString.js'
|
import { idToString } from '../helpers/idToString.js'
|
||||||
@@ -642,6 +642,8 @@ describe('Joins Field', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
expect(true).toBeTruthy()
|
||||||
const response = await restClient
|
const response = await restClient
|
||||||
.GRAPHQL_POST({ body: JSON.stringify({ query }) })
|
.GRAPHQL_POST({ body: JSON.stringify({ query }) })
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
@@ -666,6 +668,21 @@ describe('Joins Field', () => {
|
|||||||
|
|
||||||
expect(allCategories.totalDocs).toBe(allCategoriesByIds.totalDocs)
|
expect(allCategories.totalDocs).toBe(allCategoriesByIds.totalDocs)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should join with singular collection name', async () => {
|
||||||
|
const {
|
||||||
|
docs: [category],
|
||||||
|
} = await payload.find({ collection: 'categories', limit: 1, depth: 0 })
|
||||||
|
|
||||||
|
const singular = await payload.create({
|
||||||
|
collection: 'singular',
|
||||||
|
data: { category: category.id },
|
||||||
|
})
|
||||||
|
|
||||||
|
const categoryWithJoins = await payload.findByID({ collection: 'categories', id: category.id })
|
||||||
|
|
||||||
|
expect((categoryWithJoins.singulars.docs[0] as Singular).id).toBe(singular.id)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
async function createPost(overrides?: Partial<Post>, locale?: Config['locale']) {
|
async function createPost(overrides?: Partial<Post>, locale?: Config['locale']) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export interface Config {
|
|||||||
uploads: Upload;
|
uploads: Upload;
|
||||||
versions: Version;
|
versions: Version;
|
||||||
'categories-versions': CategoriesVersion;
|
'categories-versions': CategoriesVersion;
|
||||||
|
singular: Singular;
|
||||||
'localized-posts': LocalizedPost;
|
'localized-posts': LocalizedPost;
|
||||||
'localized-categories': LocalizedCategory;
|
'localized-categories': LocalizedCategory;
|
||||||
users: User;
|
users: User;
|
||||||
@@ -133,6 +134,20 @@ export interface Category {
|
|||||||
hasNextPage?: boolean | null;
|
hasNextPage?: boolean | null;
|
||||||
} | null;
|
} | null;
|
||||||
};
|
};
|
||||||
|
singulars?: {
|
||||||
|
docs?: (string | Singular)[] | null;
|
||||||
|
hasNextPage?: boolean | null;
|
||||||
|
} | null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "singular".
|
||||||
|
*/
|
||||||
|
export interface Singular {
|
||||||
|
id: string;
|
||||||
|
category?: (string | null) | Category;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
@@ -231,6 +246,10 @@ export interface PayloadLockedDocument {
|
|||||||
relationTo: 'categories-versions';
|
relationTo: 'categories-versions';
|
||||||
value: string | CategoriesVersion;
|
value: string | CategoriesVersion;
|
||||||
} | null)
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'singular';
|
||||||
|
value: string | Singular;
|
||||||
|
} | null)
|
||||||
| ({
|
| ({
|
||||||
relationTo: 'localized-posts';
|
relationTo: 'localized-posts';
|
||||||
value: string | LocalizedPost;
|
value: string | LocalizedPost;
|
||||||
|
|||||||
Reference in New Issue
Block a user