Skip to content

Instantly share code, notes, and snippets.

@tantaman
Last active March 4, 2021 20:15
Show Gist options
  • Save tantaman/a31c04d24a9e2dd2b0b29b80ea6a9a05 to your computer and use it in GitHub Desktop.
Save tantaman/a31c04d24a9e2dd2b0b29b80ea6a9a05 to your computer and use it in GitHub Desktop.
Generate short uuids in the browser

UUIDs are nice in that they're globally unique. They have problems when it comes to storage (take up > 64 bits) and performance (id space is random, leading to poor usage of B-trees).

See performance analysis here: https://www.percona.com/blog/2019/11/22/uuids-are-popular-but-bad-for-performance-lets-discuss/

We can, however, generate UUIDs that fit into the unsigned 64 bit integer space and are prefixed by timestamp to keep queries on recent data performant.

Below is a method to generate short UUIDs in the browser.

Note: we save the id as a hex string on the client. This is because a JavaScript integer cannot represent a full 64 bit unsigned value so we resort to strings on the client.

  • The server would need to convert the hex to a uint_64 before saving records received from the client.
  • The server would also need to convert uint_64 to a hex string when sending to JavaScript clients.

Both of the above should be relatively easy to do in GraphQL API handlers when coercing ID types.

We make use of a deviceId below. This could be sent in a cookie from the server or it could be a browser fingerprint. See fingerprintjs.

The implementation is based on these proposals: https://dev.mysql.com/doc/refman/5.6/en/miscellaneous-functions.html#function_uuid-short https://www.percona.com/blog/2019/11/22/uuids-are-popular-but-bad-for-performance-lets-discuss/#crayon-604006e1ec367649398457

export type SID_of<T> = string;
export type Hex = string;

let randomVariable = Math.floor(Number.MAX_SAFE_INTEGER * Math.random());
export default function sid<T>(
  deviceId: Hex,
): SID_of<T> {
  // 32 bits, hex
  const hi32 = Math.floor(Date.now() / 1000).toString(16);

  // low 16 bits of device, in hex
  const partialDevice = deviceId.substr(-4);
  // low 16 bits of the random variable, in hex
  const random = (++randomVariable & 0xFFFF).toString(16);

  const low32 = partialDevice + random;
  // return the ID in hex.
  return hi32 + low32;
}

example usage:

import sid from 'sid';

const new_user_id = sid<User>(deviceId);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment