Bulk Operations
Batch creates, updates, deletes, upsert, and optimistic locking.
Flashcore supports batch operations for working with multiple records at once, plus upsert for create-or-update logic and optimistic locking for safe concurrent updates.
createMany, updateMany, and deleteMany require an adapter with ACID support (transaction() or atomicBatch()). The default FileAdapter does not support these — use a database-backed adapter like PostgreSQL via Keyv, or install @robojs/flashcore-extras for transaction support.
Create Many
Insert multiple records in a single call:
const result = await Warning.createMany({
data: [
{ guildId: '123', userId: '456', reason: 'Spam', severity: 'low' },
{ guildId: '123', userId: '789', reason: 'Off-topic', severity: 'low' },
{ guildId: '123', userId: '456', reason: 'Harassment', severity: 'high' }
]
})
// result.count === 3const result = await Warning.createMany({
data: [
{ guildId: '123', userId: '456', reason: 'Spam', severity: 'low' },
{ guildId: '123', userId: '789', reason: 'Off-topic', severity: 'low' },
{ guildId: '123', userId: '456', reason: 'Harassment', severity: 'high' }
]
})
// result.count === 3Use skipDuplicates to silently skip records that violate unique constraints:
const result = await GuildMember.createMany({
data: members,
skipDuplicates: true
})const result = await GuildMember.createMany({
data: members,
skipDuplicates: true
})Update Many
Update all records matching a where clause:
const result = await Warning.updateMany({
where: { guildId: '123', severity: 'low' },
data: { active: false }
})
// result.count = number of records updatedconst result = await Warning.updateMany({
where: { guildId: '123', severity: 'low' },
data: { active: false }
})
// result.count = number of records updatedDelete Many
Delete all records matching a where clause:
const result = await Warning.deleteMany({
where: { guildId: '123', active: false }
})
// result.count = number of records deletedconst result = await Warning.deleteMany({
where: { guildId: '123', active: false }
})
// result.count = number of records deletedUpsert
Create a record if it does not exist, or update it if it does:
const member = await GuildMember.upsert({
where: { id: 'member-id' },
create: {
guildId: '123',
userId: '456',
nickname: 'NewUser',
xp: 0
},
update: {
nickname: 'UpdatedUser',
xp: 100
}
})const member = await GuildMember.upsert({
where: { id: 'member-id' },
create: {
guildId: '123',
userId: '456',
nickname: 'NewUser',
xp: 0
},
update: {
nickname: 'UpdatedUser',
xp: 100
}
})The where clause uses the same unique-lookup rules as findUnique — by id or by unique fields.
Optimistic Locking
Add a version field to detect concurrent modifications. The version auto-increments on each update:
import { createModel, f, TransactionConflictError } from 'robo.js/flashcore'
export const GuildSettings = createModel('GuildSettings', {
id: f.id(),
guildId: f.string().unique(),
prefix: f.string().default('!'),
version: f.number().version()
})import { createModel, f, TransactionConflictError } from 'robo.js/flashcore'
export const GuildSettings = createModel('GuildSettings', {
id: f.id(),
guildId: f.string().unique(),
prefix: f.string().default('!'),
version: f.number().version()
})Pass the expected version when updating. If the stored version has changed since you read it, a TransactionConflictError is thrown:
const settings = await GuildSettings.findUnique({
where: { guildId: '123' }
})
try {
await GuildSettings.update({
where: { id: settings.id },
data: { prefix: '?' },
version: settings.version
})
} catch (error) {
if (error instanceof TransactionConflictError) {
// Another update happened — re-read and retry
}
}const settings = await GuildSettings.findUnique({
where: { guildId: '123' }
})
try {
await GuildSettings.update({
where: { id: settings.id },
data: { prefix: '?' },
version: settings.version
})
} catch (error) {
if (error instanceof TransactionConflictError) {
// Another update happened — re-read and retry
}
}For more advanced transaction support with serial queues and automatic retries, see Transactions in @robojs/flashcore-extras.
