How to make a UUID in DynamoDB?

2020-01-29 09:51发布

In my db scheme, I need a autoincrement primary key. How I can realize this feature?

PS For access to DynamoDB, I use dynode, module for Node.js.

9条回答
甜甜的少女心
2楼-- · 2020-01-29 10:10

I don't believe it is possible to to a SQL style auto-increment because the tables are partitioned across multiple machines. I generate my own UUID in PHP which does the job, I'm sure you could come up with something similar like this in javascript.

查看更多
三岁会撩人
3楼-- · 2020-01-29 10:14

Create the new file.js and put this code:

exports.guid = function () {
    function _p8(s) {
        var p = (Math.random().toString(16)+"000000000").substr(2,8);
        return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
    }
    return (_p8() + _p8(true) + _p8(true)+new Date().toISOString().slice(0,10)).replace(/-/g,"");
}

Then you can apply this function to the primary key id. It will generate the UUID.

查看更多
贪生不怕死
4楼-- · 2020-01-29 10:18

Addition to @yadutaf's answer

AWS supports Atomic Counters.

Create a separate table (order_id) with a row holding the latest order_number:

+----+--------------+
| id | order_number |
+----+--------------+
|  0 |         5000 |
+----+--------------+

This will allow to increment order_number by 1 and get the incremented result in a callback from AWS DynamoDB:

config={
  region: 'us-east-1',
  endpoint: "http://localhost:8000"
};
const docClient = new AWS.DynamoDB.DocumentClient(config); 

let param = {
            TableName: 'order_id',
            Key: {
                "id": 0
            },
            UpdateExpression: "set order_number = order_number + :val",
            ExpressionAttributeValues:{
                ":val": 1
            },
            ReturnValues: "UPDATED_NEW"
        };


docClient.update(params, function(err, data) {
   if (err) {
                console.log("Unable to update the table. Error JSON:", JSON.stringify(err, null, 2));
   } else {
                console.log(data);
                console.log(data.Attributes.order_number); // <= here is our incremented result
    }
  });

查看更多
Evening l夕情丶
5楼-- · 2020-01-29 10:21

Disclaimer: I am the maintainer of the Dynamodb-mapper project

Intuitive workflow of an auto-increment key:

  1. get the last counter position
  2. add 1
  3. use the new number as the index of the object
  4. save the new counter value
  5. save the object

This is just to explain the underlying idea. Never do it this way because it's not atomic. Under certain workload, you may allocate the same ID to 2+ different objects because it's not atomic. This would result in a data loss.

The solution is to use the atomic ADD operation along with ALL_NEW of UpdateItem:

  1. atomically generate an ID
  2. use the new number as the index of the object
  3. save the object

In the worst case scenario, the application crashes before the object is saved but never risk to allocate the same ID twice.

There is one remaining problem: where to store the last ID value ? We chose:

{
    "hash_key"=-1, #0 was judged too risky as it is the default value for integers.
    "__max_hash_key__y"=N
}

Of course, to work reliably, all applications inserting data MUST be aware of this system otherwise you might (again) overwrite data.

the last step is to automate the process. For example:

When hash_key is 0:
    atomically_allocate_ID()
actual_save()

For implementation details (Python, sorry), see https://bitbucket.org/Ludia/dynamodb-mapper/src/8173d0e8b55d/dynamodb_mapper/model.py#cl-67

To tell you the truth, my company does not use it in production because, most of the time it is better to find another key like, for the user, an ID, for a transaction, a datetime, ...

I wrote some examples in dynamodb-mapper's documentation and it can easily be extrapolate to Node.JS

If you have any question, feel free to ask.

查看更多
forever°为你锁心
6楼-- · 2020-01-29 10:21

Auto Increment is not good from performance perspective as it will overload specific shards while keeping others idle, It doesn't make even distribution if you're storing data to Dynamodb.

awsRequestId looks like its actually V.4 UUID (Random), code snippet below to try it:

exports.handler = function(event, context, callback) {
    console.log('remaining time =', context.getRemainingTimeInMillis());
    console.log('functionName =', context.functionName);
    console.log('AWSrequestID =', context.awsRequestId);
    callback(null, context.functionName);
};

In case you want to generate this yourself, you can use https://www.npmjs.com/package/uuid or Ulide to generate different versions of UUID based on RFC-4122

  • V1 (timestamp based)
  • V3 (Namespace)
  • V4 (Random)

For Go developers, you can use these packages from Google's UUID, Pborman, or Satori. Pborman is better in performance, check these articles and benchmarks for more details.

More Info on Universal Unique Identifier Specification could be found here.

查看更多
你好瞎i
7楼-- · 2020-01-29 10:28

I've had the same problem and created a small web service just for this purpose. See this blog post, that explains how I'm using stateful.co with DynamoDB in order to simulate auto-increment functionality: http://www.yegor256.com/2014/05/18/cloud-autoincrement-counters.html

Basically, you register an atomic counter at stateful.co and increment it every time you need a new value, through RESTful API. The service is free.

查看更多
登录 后发表回答