Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
JavaScript code for generating Firebase Push IDs
/**
* Fancy ID generator that creates 20-character string identifiers with the following properties:
*
* 1. They're based on timestamp so that they sort *after* any existing ids.
* 2. They contain 72-bits of random data after the timestamp so that IDs won't collide with other clients' IDs.
* 3. They sort *lexicographically* (so the timestamp is converted to characters that will sort properly).
* 4. They're monotonically increasing. Even if you generate more than one in the same timestamp, the
* latter ones will sort after the former ones. We do this by using the previous random bits
* but "incrementing" them by 1 (only in the case of a timestamp collision).
*/
generatePushID = (function() {
// Modeled after base64 web-safe chars, but ordered by ASCII.
var PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
// Timestamp of last push, used to prevent local collisions if you push twice in one ms.
var lastPushTime = 0;
// We generate 72-bits of randomness which get turned into 12 characters and appended to the
// timestamp to prevent collisions with other clients. We store the last characters we
// generated because in the event of a collision, we'll use those same characters except
// "incremented" by one.
var lastRandChars = [];
return function() {
var now = new Date().getTime();
var duplicateTime = (now === lastPushTime);
lastPushTime = now;
var timeStampChars = new Array(8);
for (var i = 7; i >= 0; i--) {
timeStampChars[i] = PUSH_CHARS.charAt(now % 64);
// NOTE: Can't use << here because javascript will convert to int and lose the upper bits.
now = Math.floor(now / 64);
}
if (now !== 0) throw new Error('We should have converted the entire timestamp.');
var id = timeStampChars.join('');
if (!duplicateTime) {
for (i = 0; i < 12; i++) {
lastRandChars[i] = Math.floor(Math.random() * 64);
}
} else {
// If the timestamp hasn't changed since last push, use the same random number, except incremented by 1.
for (i = 11; i >= 0 && lastRandChars[i] === 63; i--) {
lastRandChars[i] = 0;
}
lastRandChars[i]++;
}
for (i = 0; i < 12; i++) {
id += PUSH_CHARS.charAt(lastRandChars[i]);
}
if(id.length != 20) throw new Error('Length should be 20.');
return id;
};
})();
@gardun0
Copy link

gardun0 commented May 3, 2018

Im so grateful finding this ❤️ thank you

@arturictus
Copy link

@adamkoncz
Copy link

Did pushid changed in firebase lately? None of the thousands of ids generated contains dash (-) or underscore (_). Or anything apart from alphanumeric characters.

@robdelacruz
Copy link

@AhmedOS
Copy link

AhmedOS commented Oct 8, 2018

Swift 4: https://gist.github.com/AhmedOS/512531b74da37f34331ecb206c77c20a
Modified version of pgherveou's one.

@franklinharvey
Copy link

franklinharvey commented Mar 7, 2019

Made a JSFiddle: https://jsfiddle.net/feLys02r/1/

It's the original script with a button to copy to clipboard.

@shen-tian
Copy link

@bhupiister
Copy link

Port in Unity C#: https://gist.github.com/bhupiister/05dbb860e9064c43e8176b591f11e555
Just paste this script into unity and assign text field and function on a button.
Thank you to the original content maker

@ghacosta
Copy link

here is the codesandox for this code!
https://codesandbox.io/s/firebase-push-id-generator-080cb

@sinuke
Copy link

sinuke commented Apr 3, 2021

@innomon
Copy link

innomon commented Jun 19, 2021

Thanks @mikelehen & @Flyclops , for sharing the code.
My usecase is that we are transforming a firebase application (which uses firebase auth) and generates an uuid based on the above algorithm, however, we needed to convert it to a W3C DID, here is a simple code

var gb64 = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
func genB32(m string) (string, error) {
  encb64 := base64.NewEncoding(gb64)
  dec, err := encb64.DecodeString(m)
  if err != nil {
    return "", err
  }  
  return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(dec), nil
}

see line Line 77 of https://play.golang.org/p/vnCZTqOjZp9

@JuliusJacobitz
Copy link

Thank you for sharing <3

@alcarazolabs
Copy link

Best way:
`
function generatePushID() {

        // Modeled after base64 web-safe chars, but ordered by ASCII.
        var PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';

        // Timestamp of last push, used to prevent local collisions if you push twice in one ms.
        var lastPushTime = 0;

        // We generate 72-bits of randomness which get turned into 12 characters and appended to the
        // timestamp to prevent collisions with other clients.  We store the last characters we
        // generated because in the event of a collision, we'll use those same characters except
        // "incremented" by one.
        var lastRandChars = [];


            var now = new Date().getTime();
            var duplicateTime = (now === lastPushTime);
            lastPushTime = now;

            var timeStampChars = new Array(8);
            for (var i = 7; i >= 0; i--) {
            timeStampChars[i] = PUSH_CHARS.charAt(now % 64);
            // NOTE: Can't use << here because javascript will convert to int and lose the upper bits.
            now = Math.floor(now / 64);
            }
            if (now !== 0) throw new Error('We should have converted the entire timestamp.');

            var id = timeStampChars.join('');

            if (!duplicateTime) {
            for (i = 0; i < 12; i++) {
                lastRandChars[i] = Math.floor(Math.random() * 64);
            }
            } else {
            // If the timestamp hasn't changed since last push, use the same random number, except incremented by 1.
            for (i = 11; i >= 0 && lastRandChars[i] === 63; i--) {
                lastRandChars[i] = 0;
            }
            lastRandChars[i]++;
            }
            for (i = 0; i < 12; i++) {
            id += PUSH_CHARS.charAt(lastRandChars[i]);
            }
            if(id.length != 20) throw new Error('Length should be 20.');

            return id;
        }
        
        console.log(generatePushID());

`

@douwevdijk
Copy link

Hi All,

Is there a possibility to have a pure numeric version?

@marcopeg
Copy link

marcopeg commented Dec 1, 2022

@chilts
Copy link

chilts commented Dec 13, 2022

Oh nice! Thanks for noting this here @marcopeg. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment