fix(plugin-search): deleting docs even when there's a published version (#10993)

Fixes https://github.com/payloadcms/payload/issues/9770

If you had a published document but then created a new draft it would
delete the search doc, this PR adds an additional find to check if an
existing published doc exists before deleting the search doc.

Also adds a few jsdocs to plugin config
This commit is contained in:
Paul
2025-02-05 15:14:17 +00:00
committed by GitHub
parent 2a1ddf1e89
commit 42da87b6e9
4 changed files with 124 additions and 10 deletions

View File

@@ -42,10 +42,25 @@ export type SearchPluginConfig = {
defaultPriorities?: {
[collection: string]: ((doc: any) => number | Promise<number>) | number
}
/**
* Controls whether drafts are deleted from the search index
*
* @default true
*/
deleteDrafts?: boolean
localize?: boolean
/**
* We use batching when re-indexing large collections. You can control the amount of items per batch, lower numbers should help with memory.
*
* @default 50
*/
reindexBatchSize?: number
searchOverrides?: { fields?: FieldsOverride } & Partial<Omit<CollectionConfig, 'fields'>>
/**
* Controls whether drafts are synced to the search index
*
* @default false
*/
syncDrafts?: boolean
}

View File

@@ -142,15 +142,42 @@ export const syncDocAsSearchIndex = async ({
}
}
if (deleteDrafts && status === 'draft') {
// do not include draft docs in search results, so delete the record
try {
await payload.delete({
id: searchDocID,
collection: searchSlug,
req,
})
} catch (err: unknown) {
payload.logger.error({ err, msg: `Error deleting ${searchSlug} document.` })
// Check to see if there's a published version of the doc
// We don't want to remove the search doc if there is a published version but a new draft has been created
const {
docs: [docWithPublish],
} = await payload.find({
collection,
draft: false,
locale: syncLocale,
req,
where: {
and: [
{
_status: {
equals: 'published',
},
},
{
id: {
equals: id,
},
},
],
},
})
if (!docWithPublish) {
// do not include draft docs in search results, so delete the record
try {
await payload.delete({
id: searchDocID,
collection: searchSlug,
req,
})
} catch (err: unknown) {
payload.logger.error({ err, msg: `Error deleting ${searchSlug} document.` })
}
}
}
} else if (doSync) {

View File

@@ -64,7 +64,7 @@ export default buildConfigWithDefaults({
searchOverrides: {
access: {
// Used for int test
delete: ({ req: { user } }) => user.email === devUser.email,
delete: ({ req: { user } }) => user?.email === devUser.email,
},
fields: ({ defaultFields }) => [
...defaultFields,

View File

@@ -133,6 +133,78 @@ describe('@payloadcms/plugin-search', () => {
expect(results).toHaveLength(0)
})
it('should not delete a search doc if a published item has a new draft but remains published', async () => {
const publishedPage = await payload.create({
collection: 'pages',
data: {
_status: 'published',
title: 'Published title!',
},
})
// wait for the search document to be potentially created
// we do not await this within the `syncToSearch` hook
await wait(200)
const { docs: results } = await payload.find({
collection: 'search',
depth: 0,
where: {
'doc.value': {
equals: publishedPage.id,
},
},
})
expect(results).toHaveLength(1)
// Create a new draft
await payload.update({
collection: 'pages',
id: publishedPage.id,
draft: true,
data: {
_status: 'draft',
title: 'Draft title!',
},
})
// This should remain with the published content
const { docs: updatedResults } = await payload.find({
collection: 'search',
depth: 0,
where: {
'doc.value': {
equals: publishedPage.id,
},
},
})
expect(updatedResults).toHaveLength(1)
await payload.update({
collection: 'pages',
id: publishedPage.id,
data: {
_status: 'draft',
title: 'Drafted again',
},
})
// Should now be deleted given we've unpublished the page
const { docs: deletedResults } = await payload.find({
collection: 'search',
depth: 0,
where: {
'doc.value': {
equals: publishedPage.id,
},
},
})
expect(deletedResults).toHaveLength(0)
})
it('should sync changes made to an existing search document', async () => {
const pageToReceiveUpdates = await payload.create({
collection: 'pages',