node.js 如何在 DynamoDB 中创建 UUID?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11721308/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make a UUID in DynamoDB?
提问by NiLL
采纳答案by yadutaf
Disclaimer: I am the maintainer of the Dynamodb-mapper project
免责声明:我是 Dynamodb-mapper 项目的维护者
Intuitive workflow of an auto-increment key:
自增键的直观工作流程:
- get the last counter position
- add 1
- use the new number as the index of the object
- save the new counter value
- save the object
- 获取最后一个计数器位置
- 加1
- 使用新编号作为对象的索引
- 保存新的计数器值
- 保存对象
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.
这只是为了解释基本的想法。永远不要这样做,因为它不是原子的。在某些工作负载下,您可能会将相同的 ID 分配给 2 个以上不同的对象,因为它不是原子的。这将导致数据丢失。
The solution is to use the atomic ADDoperation along with ALL_NEWof UpdateItem:
解决方案是使用原子 ADD操作以及UpdateItem的ALL_NEW:
- atomically generate an ID
- use the new number as the index of the object
- save the object
- 原子地生成一个 ID
- 使用新编号作为对象的索引
- 保存对象
In the worst case scenario, the application crashes before the object is saved but never risk to allocate the same ID twice.
在最坏的情况下,应用程序在保存对象之前崩溃,但绝不会冒险分配相同的 ID 两次。
There is one remaining problem: where to store the last ID value ? We chose:
还有一个问题:最后一个 ID 值存储在哪里?我们选择了:
{
"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
有关实现细节(Python,抱歉),请参阅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, ...
说实话,我的公司不会在生产中使用它,因为在大多数情况下,最好找到另一个键,例如,对于用户,ID,对于交易,日期时间,......
I wrote some examples in dynamodb-mapper's documentationand it can easily be extrapolate to Node.JS
我在dynamodb-mapper 的文档中写了一些例子,它可以很容易地外推到 Node.JS
If you have any question, feel free to ask.
如果您有任何问题,请随时提出。
回答by pisomojado
If you're okay with gaps in your incrementing id, and you're okay with it only roughly corresponding to the order in which the rows were added, you can roll your own: Create a separate table called NextIdTable, with one primary key (numeric), call it Counter.
如果您可以接受递增 id 中的间隙,并且您可以接受它仅与添加行的顺序大致对应,您可以自己滚动:创建一个名为 NextIdTable 的单独表,带有一个主键 (数字),称之为计数器。
Each time you want to generate a new id, you would do the following:
每次要生成新 id 时,您都需要执行以下操作:
- Do a GetItem on NextIdTable to read the current value of Counter --> curValue
- Do a PutItem on NextIdTable to set the value of Counter to curValue + 1. Make this a conditional PutItem so that it will fail if the value of Counter has changed.
- If that conditional PutItem failed, it means someone else was doing this at the same time as you were. Start over.
- If it succeeded, then curValue is your new unique ID.
- 在 NextIdTable 上执行 GetItem 以读取 Counter --> curValue 的当前值
- 在 NextIdTable 上执行 PutItem 以将 Counter 的值设置为 curValue + 1。将其设为有条件的 PutItem,以便在 Counter 的值更改时它将失败。
- 如果该条件 PutItem 失败,则意味着其他人与您同时执行此操作。重来。
- 如果成功,则 curValue 是您新的唯一 ID。
Of course, if your process crashes before actually applying that ID anywhere, you'll "leak" it and have a gap in your sequence of IDs. And if you're doing this concurrently with some other process, one of you will get value 39 and one of you will get value 40, and there are no guarantees about which order they will actually be applied in your data table; the guy who got 40 might write it before the guy who got 39. But it does give you a rough ordering.
当然,如果您的进程在实际将该 ID 应用于任何地方之前崩溃,您将“泄漏”它并在您的 ID 序列中出现间隙。如果您与某个其他进程同时执行此操作,则其中一个将获得值 39,另一个将获得值 40,并且无法保证它们将实际应用于您的数据表中的顺序;得 40 的人可能比得 39 的人先写。但它确实给了你一个粗略的排序。
Parameters for a conditional PutItem in node.js are detailed here. http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html#!AWS/DynamoDB.html. If you had previously read a value of 38 from Counter, your conditional PutItem request might look like this.
此处详细介绍了 node.js 中条件 PutItem 的参数。 http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html#!AWS/DynamoDB.html。如果您之前从 Counter 读取了 38 的值,则您的条件 PutItem 请求可能如下所示。
var conditionalPutParams = {
TableName: 'NextIdTable',
Item: {
Counter: {
N: '39'
}
},
Expected: {
Counter: {
AttributeValueList: [
{
N: '38'
}
],
ComparisonOperator: 'EQ'
}
}
};
回答by James
Another approach is to use a UUIDgenerator for primary keys, as these are highlyunlikely to clash.
另一种方法是UUID为主键使用生成器,因为它们极不可能发生冲突。
IMO you are more likely to experience errors consolidating primary key counters across highly available DynamoDBtables than from clashes in generated UUIDs.
IMODynamoDB与生成UUID的冲突相比,在跨高可用表合并主键计数器时更容易遇到错误。
For example, in Node:
例如,在节点中:
npm install uuid
npm install uuid
var uuid = require('uuid');
// Generate a v1 (time-based) id
uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'
// Generate a v4 (random) id
uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'
Taken from SO answer.
取自 SO答案。
回答by F_SO_K
For those coding in Java, DynamoDBMappercan now generate unique UUIDs on your behalf.
对于那些使用 Java 编码的人,DynamoDBMapper现在可以代表您生成唯一的 UUID。
DynamoDBAutoGeneratedKey
Marks a partition key or sort key property as being auto-generated. DynamoDBMapper will generate a random UUID when saving these attributes. Only String properties can be marked as auto-generated keys.
DynamoDBAutoGeneratedKey
将分区键或排序键属性标记为自动生成。DynamoDBMapper 将在保存这些属性时生成一个随机 UUID。只有字符串属性可以标记为自动生成的键。
Use the DynamoDBAutoGeneratedKeyannotation like this
像这样使用DynamoDBAutoGeneratedKey注释
@DynamoDBTable(tableName="AutoGeneratedKeysExample")
public class AutoGeneratedKeys {
private String id;
@DynamoDBHashKey(attributeName = "Id")
@DynamoDBAutoGeneratedKey
public String getId() { return id; }
public void setId(String id) { this.id = id; }
As you can see in the example above, you can apply both the DynamoDBAutoGeneratedKey and DynamoDBHashKey annotation to the same attribute to generate a unique hash key.
正如您在上面的示例中看到的,您可以将 DynamoDBAutoGeneratedKey 和 DynamoDBHashKey 注释应用于同一属性以生成唯一的哈希键。
回答by greg
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 thisin javascript.
我不相信 SQL 风格的自动增量是可能的,因为表是跨多台机器分区的。我生成PHP我自己的UUID其做工作,我相信你能想出一些类似这样的JavaScript。
回答by Artru
Addition to @yadutaf's answer
除了@yadutaf 的回答
AWS supports Atomic Counters.
AWS 支持原子计数器。
Create a separate table (order_id) with a row holding the latest order_number:
创建一个单独的表 ( order_id),其中一行包含最新的 order_number:
+----+--------------+
| id | order_number |
+----+--------------+
| 0 | 5000 |
+----+--------------+
This will allow to increment order_number by 1and get the incremented result in a callback from AWS DynamoDB:
这将允许增加 order_number1并从 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
}
});
Be aware that in some rarecases their might be problems with the connection between your caller point and AWS API. It will result in the dynamodb row being incremented, while you will get a connection error. Thus, there might appear some unused incremented values.
请注意,在极少数情况下,它们可能是您的调用方点和 AWS API 之间的连接出现问题。这将导致 dynamodb 行增加,同时您将收到连接错误。因此,可能会出现一些未使用的增量值。
You can use incremented data.Attributes.order_numberin your table, e.g. to insert {id: data.Attributes.order_number, otherfields:{}}into ordertable.
您可以data.Attributes.order_number在表中使用 incremented ,例如插入{id: data.Attributes.order_number, otherfields:{}}到order表中。
回答by yegor256
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.cowith DynamoDB in order to simulate auto-increment functionality: http://www.yegor256.com/2014/05/18/cloud-autoincrement-counters.html
我遇到了同样的问题,为此创建了一个小型 Web 服务。请参阅此博客文章,其中解释了我如何将stateful.co与 DynamoDB 结合使用以模拟自动增量功能:http://www.yegor256.com/2014/05/18/cloud-autoincrement-counters.html
Basically, you register an atomic counter at stateful.coand increment it every time you need a new value, through RESTful API. The service is free.
基本上,您在stateful.co注册一个原子计数器,并在每次需要新值时通过 RESTful API 递增它。该服务是免费的。
回答by Muhammad Soliman
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.
从性能角度来看,自动增量并不好,因为它会使特定分片过载,同时让其他分片保持空闲,如果您将数据存储到 Dynamodb,它不会进行均匀分布。
awsRequestIdlooks like its actually V.4 UUID (Random), code snippet below to try it:
awsRequestId看起来它实际上是 V.4 UUID(随机),下面的代码片段可以尝试:
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/uuidor Ulideto generate different versions of UUID based on RFC-4122
如果你想自己生成这个,你可以使用https://www.npmjs.com/package/uuid或Ulide根据RFC-4122生成不同版本的 UUID
- V1 (timestamp based)
- V3 (Namespace)
- V4 (Random)
- V1(基于时间戳)
- V3(命名空间)
- V4(随机)
For Go developers, you can use these packages from Google's UUID, Pborman, or Satori. Pborman is better in performance, check these articles and benchmarksfor more details.
对于 Go 开发人员,您可以使用Google 的 UUID、 Pborman或Satori 中的这些包。Pborman 的性能更好,请查看这些文章和基准以获取更多详细信息。
More Info on Universal Unique Identifier Specification could be found here.
可以在此处找到有关通用唯一标识符规范的更多信息。
回答by Jivi
Create the new file.jsand put this code:
创建新的file.js并放置以下代码:
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.
然后您可以将此函数应用于主键 id。它将生成 UUID。

