可排序的UUID v1用于多平台应用程序

4
我们正在寻找一种解决方案,为Web、iOS和Android客户端之间交换的消息/信号生成唯一的标识符,并在后端进行持久化。
  • 解决方案必须是标准化的

  • 可用于多个平台

  • 可以按创建时间排序,数据库可索引

除了一件小事,UUID v1具有这些属性,即排序和索引需要重新排列字符串标识符。

UUID文档解释了时间块的顺序是相反的(从毫秒开始)(link)。

  UUID                   = time-low "-" time-mid "-"
                           time-high-and-version "-"
                           clock-seq-and-reserved
                           clock-seq-low "-" node
  time-low               = 4hexOctet
  time-mid               = 2hexOctet
  time-high-and-version  = 2hexOctet
  clock-seq-and-reserved = hexOctet
  clock-seq-low          = hexOctet
  node                   = 6hexOctet

由于UUID表示法的存在,我们无法仅通过ID的字符串表示对其进行排序,因此我们必须使用比较函数。
const toSortableUUID = uuidV1 =>
  uuidV1.replace(/^(.{8})-(.{4})-(.{4})/, '$3-$2-$1');

const uuidCompare = (uuidV1A, uuidV1B) => {
  if (uuidV1A === uuidV1B) {
    return 0;
  }
  const a = toSortableUUID(uuidV1A);
  const b = toSortableUUID(uuidV1B);
  return a < b ? -1 : 1;
};

const sortedArrayOfUUIDV1 = arrayOfUUIDV1.concat().sort(uuidCompare);

你知道另一种标准化方法,不会有这个问题吗?

如果使用UUID v1但在客户端之间重新排列它,这样客户端可以按字符串表示进行排序,而不必每次都使用比较函数进行排序,这样做是否正确?

实时测试:https://codesandbox.io/s/q5oRxgnp

3个回答

4
如果您重新排列UUID的位,那么您将不再拥有一个UUID。此外,需要注意的是UUID标准的一个目的是允许混合不同版本的UUID值。换句话说,通常不应假设您的UUID完全属于一个版本。
UUID从未旨在被拆开,也不应被视为容器。那些考虑这样做的聪明程序员过于聪明了。尽管如此,仍有一些人会更改其UUID的结构或内容。我不建议这样做。
相反,我建议您确定并分离自己的关注点。
- 标识符 如果您需要在没有与集中式服务器协调的情况下唯一标识实体,则使用正确的UUID。 - 排序 如果您还想进行排序,则添加另一个字段以用作排序值。例如,如果您想按时间顺序排序,请存储时间戳值(如果数据库或数据接收器支持)。如果不支持,请在标准ISO 8601格式中存储UTC中日期时间值的文本表示形式。此格式经过明智地设计,以便按字母顺序排序时也是按时间顺序排列的。

2017-01-23T01:23:45.123Z


1
我提议更改应用程序当前规范。当前规范使用DateTime精度到秒,我建议改为ISO 8601。https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString我希望还可以使用ID进行排序,我了解UUID v4是完全随机的,那么使用完全随机的UUID有什么好处呢?我希望使用与Firebase相同结构的标准化ID。它以时间戳开头并以随机数据结尾。 - Marcel Mandatory

1
你似乎在寻找一个用JS编写的COMB(合并时间-GUID)编解码器。
uuid js lib问题中有一场非常长的辩论,最终在一个需要实现草案RFC的线程上结束。
在等待期间,您可以使用这个实现,它可能适合您的需求。
但是这个UUIDv7(草案RFC)实现uuid js的活跃贡献者开发,也非常有趣。
此处所解释的那样,它提供了UUIDv1UUIDv4之间的混合:

正如你所读到的,“有序UUID”有点新。它介于UUID v1(基于时间,可猜测)和UUID v4(基于随机数,不可能猜测)之间。使这个UUID特殊的是...它可以方便地排序

如果您想了解COMB的一些优缺点(仅从数据库方面),此文章在Ramsey的实现中提到。但由于它比较旧,没有考虑到分布式系统的新情况。
考虑到分布式环境,它们谈论实现运行脚本的机器ID以避免冲突,但与Uuid v1不同,不使用mac地址。
最后,这里有一个非常简单的解释,介绍了UUID v1v4v5之间的区别。

0

主要答案有点误导我,让我走了弯路,所以我想在这里澄清一些事情。

  1. 排序 - 不推荐重新排列UUID,但这并不意味着您不能按值进行排序。Cassandra就是这样做的,而且完全有效。他们基本上使用与OP建议的相同方法,但仅作为排序函数。
  2. 重新排列 - 如果您正在构建一个完全受控制的系统,则重新排列UUID虽然不被推荐,但仍将正常工作并且完全唯一。假设您均匀地执行此操作,它可能不是普遍唯一的,但在您的系统中是唯一的。

定义自定义排序函数

如上所述,Cassandra已经定义了一个内置的排序函数,用于对UUID进行排序。如果您具备能力,可以在其他系统中执行相同的操作,但作为JavaScript的标准示例,给定以下UUId,您可以像这样进行排序:

// Rearrange, only used for the purpose of sorting
const rearrangeId = uuid => {
  let [low, mid, hiAndVersion] = uuid.split('-')

  return [hiAndVersion, mid, low].join('')
}

// Sorting, using our rearrange function
uuids.sort((id1, id2) => {
  let rearranged1 = rearrangeId(id1)
  let rearranged2 = rearrangeId(id2)

  if (rearranged1 > rearranged2) {
    return 1
  }

  return -1
}

希望这能对某人有所帮助!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接