LogoRobo.js

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 === 3
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 === 3

Use 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 updated
const result = await Warning.updateMany({
	where: { guildId: '123', severity: 'low' },
	data: { active: false }
})
// result.count = number of records updated

Delete Many

Delete all records matching a where clause:

const result = await Warning.deleteMany({
	where: { guildId: '123', active: false }
})
// result.count = number of records deleted
const result = await Warning.deleteMany({
	where: { guildId: '123', active: false }
})
// result.count = number of records deleted

Upsert

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.

On this page