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,
|
collection: collectionSlug,
|
||||||
data,
|
data,
|
||||||
|
limit,
|
||||||
locale,
|
locale,
|
||||||
options: optionsArgs = {},
|
options: optionsArgs = {},
|
||||||
req,
|
req,
|
||||||
@@ -37,7 +38,7 @@ export const updateMany: UpdateMany = async function updateMany(
|
|||||||
session: await getSession(this, req),
|
session: await getSession(this, req),
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = await buildQuery({
|
let query = await buildQuery({
|
||||||
adapter: this,
|
adapter: this,
|
||||||
collectionSlug,
|
collectionSlug,
|
||||||
fields: collectionConfig.flattenedFields,
|
fields: collectionConfig.flattenedFields,
|
||||||
@@ -48,6 +49,19 @@ export const updateMany: UpdateMany = async function updateMany(
|
|||||||
transform({ adapter: this, data, fields: collectionConfig.fields, operation: 'write' })
|
transform({ adapter: this, data, fields: collectionConfig.fields, operation: 'write' })
|
||||||
|
|
||||||
try {
|
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)
|
await Model.updateMany(query, data, options)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError({ collection: collectionSlug, error, req })
|
handleError({ collection: collectionSlug, error, req })
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export const updateMany: UpdateMany = async function updateMany(
|
|||||||
collection: collectionSlug,
|
collection: collectionSlug,
|
||||||
data,
|
data,
|
||||||
joins: joinQuery,
|
joins: joinQuery,
|
||||||
|
limit,
|
||||||
locale,
|
locale,
|
||||||
req,
|
req,
|
||||||
returning,
|
returning,
|
||||||
@@ -55,12 +56,21 @@ export const updateMany: UpdateMany = async function updateMany(
|
|||||||
|
|
||||||
const table = this.tables[tableName]
|
const table = this.tables[tableName]
|
||||||
|
|
||||||
const docsToUpdate = await _db
|
const docsToUpdate =
|
||||||
.select({
|
typeof limit === 'number' && limit > 0
|
||||||
id: table.id,
|
? await _db
|
||||||
})
|
.select({
|
||||||
.from(table)
|
id: table.id,
|
||||||
.where(where)
|
})
|
||||||
|
.from(table)
|
||||||
|
.where(where)
|
||||||
|
.limit(limit)
|
||||||
|
: await _db
|
||||||
|
.select({
|
||||||
|
id: table.id,
|
||||||
|
})
|
||||||
|
.from(table)
|
||||||
|
.where(where)
|
||||||
|
|
||||||
idsToUpdate = docsToUpdate?.map((doc) => doc.id)
|
idsToUpdate = docsToUpdate?.map((doc) => doc.id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -517,6 +517,7 @@ export type UpdateManyArgs = {
|
|||||||
data: Record<string, unknown>
|
data: Record<string, unknown>
|
||||||
draft?: boolean
|
draft?: boolean
|
||||||
joins?: JoinQuery
|
joins?: JoinQuery
|
||||||
|
limit?: number
|
||||||
locale?: string
|
locale?: string
|
||||||
/**
|
/**
|
||||||
* Additional database adapter specific options to pass to the query
|
* Additional database adapter specific options to pass to the query
|
||||||
|
|||||||
@@ -960,6 +960,183 @@ describe('database', () => {
|
|||||||
expect(notUpdatedDocs).toHaveLength(1)
|
expect(notUpdatedDocs).toHaveLength(1)
|
||||||
expect(notUpdatedDocs?.[0]?.title).toBe('notupdated')
|
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', () => {
|
describe('Error Handler', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user