How to auto-increment orderNumber field when creating new order document?
The best approach for auto-incrementing an orderNumber field is to use a dedicated counter document with atomic transactions. Here's the pattern that works reliably:
Solution: Counter Document with Atomic Transactions
Create a separate counter document to track your order numbers, then use transactions with patch, setIfMissing, and inc operations to atomically increment and retrieve the next number:
async function createOrder() {
const COUNTER_ID = 'order-counter'; // A fixed document ID for your counter
// Atomic transaction to get next order number
const result = await client
.transaction()
.patch(COUNTER_ID, patch =>
patch
.setIfMissing({ _type: 'counter', current: 2300000000 }) // Initialize if missing
.inc({ current: 1 }) // Increment atomically
)
.commit({ returnDocuments: true });
const nextOrderNumber = result[0].current;
// Now create your order with the guaranteed unique number
const doc = {
_type: 'order',
note: 'První poznámka objednávky',
orderNumber: nextOrderNumber,
};
const orderResult = await client.create(doc);
console.log(`Objednávka byla vytvořena, document ID is ${orderResult._id}`);
console.log(`Order number: ${nextOrderNumber}`);
}Why This Works
setIfMissingensures the counter document exists and is initialized on first useincatomically increments the counter - this is thread-safe even with concurrent requestsreturnDocuments: truegives you the updated counter value immediately- The transaction ensures atomicity - no race conditions even if multiple orders are created simultaneously
Alternative: Single Transaction (More Efficient)
You can also create both the counter update and order document in a single transaction:
async function createOrder() {
const COUNTER_ID = 'order-counter';
const orderId = `order-${Date.now()}`; // Generate unique ID
// First get the next number
const counterResult = await client
.transaction()
.patch(COUNTER_ID, patch =>
patch
.setIfMissing({ _type: 'counter', current: 2300000000 })
.inc({ current: 1 })
)
.commit({ returnDocuments: true });
const nextOrderNumber = counterResult[0].current;
// Then create the order with that number
const orderResult = await client.create({
_type: 'order',
note: 'První poznámka objednávky',
orderNumber: nextOrderNumber,
});
console.log(`Objednávka byla vytvořena, document ID is ${orderResult._id}`);
return orderResult;
}Don't Forget Your Schema
Add a counter document type to your schema:
export default {
name: 'counter',
type: 'document',
title: 'Counter',
fields: [
{
name: 'current',
type: 'number',
title: 'Current Value',
},
],
}Why Not Use GROQ math::sum?
While GROQ's math::sum can calculate totals, it's not suitable for generating unique sequential numbers because:
- There's a race condition between querying the max value and creating the new document
- Multiple concurrent requests could get the same "next" number
- GROQ queries are read-only and can't atomically increment
The counter document with inc is the proper solution because it's atomic and handles concurrency correctly. The ifRevisionId parameter you might find in older examples is not necessary with this approach since inc is inherently atomic within a transaction.
Show original thread4 replies
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.