0

I am new to dynamodb.

I want to increment the Sort Key

If the id=0 the next id=1 and so on,

If the user(Partition key), id(Sort Key) add items the next add items the id increment 1.

The code use on PutItem with dynamodb.

Is possible to do that?

I did not want use the UUID( unique Key)

Zoe
  • 27,060
  • 21
  • 118
  • 148
M H
  • 11
  • 1
  • Please provide enough code so others can better understand or reproduce the problem. – Community Oct 17 '21 at 05:28
  • could provide us with some more explanation about why UUID isn't a good solution. Is it because you want to order them in order of creation ? Or is it because of some legal obligation ? – bvdb Aug 05 '22 at 11:16

2 Answers2

1

Most situations don't need an auto-incrementing attribute and DynamoDB doesn't provide this feature out of the box. This is considered to be an anti-pattern in distributed systems.

But, see How to autoincrement in DynamoDB if you really need to.

jarmod
  • 71,565
  • 16
  • 115
  • 122
0

I understand that you may need this number because it is a legal obligation to have incremental invoice numbers for example.

One way would be to create a table to store your number sequences. Add fields like:

{
  name: "invoices",
  prefix: "INV",
  numberOfDigits: 5,
  leasedValue: 1,
  appliedValue: 1,
  lastUpdatedTime: '2022-08-05'
},
{
  name: "deliveryNotes",
  prefix: "DN",
  numberOfDigits: 5,
  leasedValue: 1,
  appliedValue: 1,
  lastUpdatedTime: '2022-08-05'
}

You need 2 values (a lease and an applied value), to make sure you never skip a beat, even when things go wrong.

That check-lease-apply-release/rollback logic looks as follows:

async function useSequence(name: string, cb: async (uniqueNumber: string) => void) {
  // 1. GET THE SEQUENCE FROM DATABASE
  const sequence = await getSequence("invoices");
  this.validateSequence(sequence);

  // 2. INCREASE THE LEASED VALUE
  const oldValue = sequence.appliedValue;
  const leasedValue = oldValue + 1;
  sequence.leasedValue = leasedValue;
  await saveSequence(sequence);

  try {

    // 3. CREATE AND SAVE YOUR DOCUMENT
    await cb(format(leasedValue));

    // 4. INCREASE THE APPLIED VALUE
    sequence.appliedValue++;
    await saveSequence(sequence);

  } catch(err) {
     // 4B. ROLLBACK WHEN THINGS ARE BROKEN
     console.err(err)
     try {
       const sequence = await getSequence(name);
       sequence.leasedValue--;
       this.validateSequence(sequence);
       await saveSequence(sequence);
     } catch (err2) {
       console.error(err2);
     }
     throw err;
  }
}

function validateSequence(sequence) {
  // A CLEAN STATE, MEANS THAT THE NUMBERS ARE IN SYNC
  if (sequence.leasedValue !== sequence.appliedValue) {
    throw new Error("sequence is broken.");
  }
}

Then, whenever you need a unique number you can use the above function to work in a protected scope, where the number will be rollbacked when something goes wrong.

const details = ...;
await useSequence("invoice", async (uniqueNumber) => {
  const invoiceData = {...details, id: uniqueNumber};
  const invoice = await this.createInvoice(invoiceData);
  await this.saveInvoice(invoice);
})

Can it scale? Can it run on multiple instances? No, it can't. It never will be, because in most countries it's just not legal to do so. You're not allowed to send out invoice 6 before invoice 5 or to cancel invoice 5 after you've send invoice 6.

The only exception being, if you have multiple sequences. e.g. in some cases you're allowed to have a sequence per customer, or a sequence per payment system, ... Hence, you want them in your database.

bvdb
  • 22,839
  • 10
  • 110
  • 123