How to auto-increment orderNumber field when creating new order document?

4 replies
Last updated: Nov 29, 2025
Dear support, comunity,what is easiest way to get/write next number of array - field "orderNumber"
Example of object order:
{
"_createdAt": "2022-12-14T19
:04:58Z", "_id": "4db5796f-ed83-411d-b419-bf668206b3ce",
"_rev": "j1tWZCfjdAwUaXU7wQg1DG",
"_type": "order",
"_updatedAt": "2022-12-14T19
:14:25Z", "note": "erer",
"orderNumber": 2300000001
}

I would like to write next number of field "orderNumber" in the moment when i run function "createOrder"
function createOrder() {

const doc = {
_type: 'order',
note: 'První poznámka objednávky',
order_number: novaObj,
}
console.log(novaObj);
client.create(doc).then((res) => {
console.log(
Objednávka byla vytvořena , document ID is ${res._id}
) });
}
----

What i found
https://www.sanity.io/docs/groq-functions#03c444f2caf3
math::sum(<array[number]>) <number|null>
and
https://www.sanity.io/docs/initial-value-templates
Thank you
AI Update

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

  1. setIfMissing ensures the counter document exists and is initialized on first use
  2. inc atomically increments the counter - this is thread-safe even with concurrent requests
  3. returnDocuments: true gives you the updated counter value immediately
  4. 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 thread
4 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.

Was this answer helpful?