feat(db-*): support limit in db.updateMany (#11488)
This PR adds a new `limit` property to `payload.db.updateMany`. This functionality is required for [migrating our job system to use faster, direct db adapter calls](https://github.com/payloadcms/payload/pull/11489)
This commit is contained in:
@@ -15,6 +15,7 @@ export const updateMany: UpdateMany = async function updateMany(
|
||||
{
|
||||
collection: collectionSlug,
|
||||
data,
|
||||
limit,
|
||||
locale,
|
||||
options: optionsArgs = {},
|
||||
req,
|
||||
@@ -37,7 +38,7 @@ export const updateMany: UpdateMany = async function updateMany(
|
||||
session: await getSession(this, req),
|
||||
}
|
||||
|
||||
const query = await buildQuery({
|
||||
let query = await buildQuery({
|
||||
adapter: this,
|
||||
collectionSlug,
|
||||
fields: collectionConfig.flattenedFields,
|
||||
@@ -48,6 +49,19 @@ export const updateMany: UpdateMany = async function updateMany(
|
||||
transform({ adapter: this, data, fields: collectionConfig.fields, operation: 'write' })
|
||||
|
||||
try {
|
||||
if (typeof limit === 'number' && limit > 0) {
|
||||
const documentsToUpdate = await Model.find(
|
||||
query,
|
||||
{},
|
||||
{ ...options, limit, projection: { _id: 1 } },
|
||||
)
|
||||
if (documentsToUpdate.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
query = { _id: { $in: documentsToUpdate.map((doc) => doc._id) } }
|
||||
}
|
||||
|
||||
await Model.updateMany(query, data, options)
|
||||
} catch (error) {
|
||||
handleError({ collection: collectionSlug, error, req })
|
||||
|
||||
@@ -16,6 +16,7 @@ export const updateMany: UpdateMany = async function updateMany(
|
||||
collection: collectionSlug,
|
||||
data,
|
||||
joins: joinQuery,
|
||||
limit,
|
||||
locale,
|
||||
req,
|
||||
returning,
|
||||
@@ -55,7 +56,16 @@ export const updateMany: UpdateMany = async function updateMany(
|
||||
|
||||
const table = this.tables[tableName]
|
||||
|
||||
const docsToUpdate = await _db
|
||||
const docsToUpdate =
|
||||
typeof limit === 'number' && limit > 0
|
||||
? await _db
|
||||
.select({
|
||||
id: table.id,
|
||||
})
|
||||
.from(table)
|
||||
.where(where)
|
||||
.limit(limit)
|
||||
: await _db
|
||||
.select({
|
||||
id: table.id,
|
||||
})
|
||||
|
||||
@@ -517,6 +517,7 @@ export type UpdateManyArgs = {
|
||||
data: Record<string, unknown>
|
||||
draft?: boolean
|
||||
joins?: JoinQuery
|
||||
limit?: number
|
||||
locale?: string
|
||||
/**
|
||||
* Additional database adapter specific options to pass to the query
|
||||
|
||||
@@ -960,6 +960,183 @@ describe('database', () => {
|
||||
expect(notUpdatedDocs).toHaveLength(1)
|
||||
expect(notUpdatedDocs?.[0]?.title).toBe('notupdated')
|
||||
})
|
||||
|
||||
it('ensure updateMany respects limit', async () => {
|
||||
await payload.db.deleteMany({
|
||||
collection: postsSlug,
|
||||
where: {
|
||||
id: {
|
||||
exists: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Create 11 posts
|
||||
for (let i = 0; i < 11; i++) {
|
||||
await payload.create({
|
||||
collection: postsSlug,
|
||||
data: {
|
||||
title: 'not updated',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const result = await payload.db.updateMany({
|
||||
collection: postsSlug,
|
||||
data: {
|
||||
title: 'updated',
|
||||
},
|
||||
limit: 5,
|
||||
where: {
|
||||
id: {
|
||||
exists: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(result?.length).toBe(5)
|
||||
expect(result?.[0]?.title).toBe('updated')
|
||||
expect(result?.[4]?.title).toBe('updated')
|
||||
|
||||
// Ensure all posts minus the one we don't want updated are updated
|
||||
const { docs } = await payload.find({
|
||||
collection: postsSlug,
|
||||
depth: 0,
|
||||
pagination: false,
|
||||
where: {
|
||||
title: {
|
||||
equals: 'updated',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(docs).toHaveLength(5)
|
||||
expect(docs?.[0]?.title).toBe('updated')
|
||||
expect(docs?.[4]?.title).toBe('updated')
|
||||
|
||||
const { docs: notUpdatedDocs } = await payload.find({
|
||||
collection: postsSlug,
|
||||
depth: 0,
|
||||
pagination: false,
|
||||
where: {
|
||||
title: {
|
||||
equals: 'not updated',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(notUpdatedDocs).toHaveLength(6)
|
||||
expect(notUpdatedDocs?.[0]?.title).toBe('not updated')
|
||||
expect(notUpdatedDocs?.[5]?.title).toBe('not updated')
|
||||
})
|
||||
|
||||
it('ensure updateMany correctly handles 0 limit', async () => {
|
||||
await payload.db.deleteMany({
|
||||
collection: postsSlug,
|
||||
where: {
|
||||
id: {
|
||||
exists: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Create 5 posts
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await payload.create({
|
||||
collection: postsSlug,
|
||||
data: {
|
||||
title: 'not updated',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const result = await payload.db.updateMany({
|
||||
collection: postsSlug,
|
||||
data: {
|
||||
title: 'updated',
|
||||
},
|
||||
limit: 0,
|
||||
where: {
|
||||
id: {
|
||||
exists: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(result?.length).toBe(5)
|
||||
expect(result?.[0]?.title).toBe('updated')
|
||||
expect(result?.[4]?.title).toBe('updated')
|
||||
|
||||
// Ensure all posts are updated. limit: 0 should mean unlimited
|
||||
const { docs } = await payload.find({
|
||||
collection: postsSlug,
|
||||
depth: 0,
|
||||
pagination: false,
|
||||
where: {
|
||||
title: {
|
||||
equals: 'updated',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(docs).toHaveLength(5)
|
||||
expect(docs?.[0]?.title).toBe('updated')
|
||||
expect(docs?.[4]?.title).toBe('updated')
|
||||
})
|
||||
|
||||
it('ensure updateMany correctly handles -1 limit', async () => {
|
||||
await payload.db.deleteMany({
|
||||
collection: postsSlug,
|
||||
where: {
|
||||
id: {
|
||||
exists: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Create 5 posts
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await payload.create({
|
||||
collection: postsSlug,
|
||||
data: {
|
||||
title: 'not updated',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const result = await payload.db.updateMany({
|
||||
collection: postsSlug,
|
||||
data: {
|
||||
title: 'updated',
|
||||
},
|
||||
limit: -1,
|
||||
where: {
|
||||
id: {
|
||||
exists: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(result?.length).toBe(5)
|
||||
expect(result?.[0]?.title).toBe('updated')
|
||||
expect(result?.[4]?.title).toBe('updated')
|
||||
|
||||
// Ensure all posts are updated. limit: -1 should mean unlimited
|
||||
const { docs } = await payload.find({
|
||||
collection: postsSlug,
|
||||
depth: 0,
|
||||
pagination: false,
|
||||
where: {
|
||||
title: {
|
||||
equals: 'updated',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(docs).toHaveLength(5)
|
||||
expect(docs?.[0]?.title).toBe('updated')
|
||||
expect(docs?.[4]?.title).toBe('updated')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Error Handler', () => {
|
||||
|
||||
Reference in New Issue
Block a user