0

I'm building a Firebase project that requires the use of sequential IDs. These IDs must also be short and numeric (ex. 633521).

After reading the documentation I learned that sequential IDs are a performance risk and lead to hotspotting.

The problem is I've already built much of the app's infrastructure using sequential IDs. Here's the code I've written to generate these short numeric ID's:

const generateUniqueId = async (parentId, tries = 1) => {
    try {
        if (tries > 3) return false;

        const zeroPad = (num, places) => String(num).padStart(places, '0');
        const id = zeroPad(Math.floor(Math.random() * 999999), 6);

        await DB.collection('parent')
            .doc(parentId)
            .collection('child')
            .doc(id)
            .create({ id });

        return id;
    } catch (error) {
        if (error.code === 6) {
            return await generateUniqueId(parentId, tries + 1);
        } else {
            return false;
        }
    }
};

This isn't the most elegant solution, but this was the best I could come up with due to Firebase's lack of support for sequential IDs. Essentially what's happening here is I generate a random 6 digit number, then I check if a document already exists with that number.

But after discovering the inherent risk of sequential ID's I'm wondering if this is still a viable solution (or ever was). Does this need to be refactored or could I get away with a small performance hit in exchange for functionality? The collection size will most likely never exceed a few thousand documents if that matters.

Update:

I simply confused the word "sequential" with "numeric," a very silly mistake while reading the documentation. Somehow I believed numeric IDs could lead to hotspotting, without realizing they needed to be sequential. So there's nothing wrong with the code above. Sorry for the confusion.

  • 2
    "could I get away with a small performance hit in exchange for functionality?" Unless you can specify what your exact performance requirements are, it's going to be hard for us to answer this for you. – Frank van Puffelen Aug 24 '21 at 15:13
  • Basically is this going cost an absurd amount of money? I want to know just how badly this will scale. – Andrew Eyesman Aug 24 '21 at 15:14
  • At a certain point all 6 digits numbers maybe taken and it will cost you 3 reads every time a user tries to create a new document. Make sure you handle that condition. – Dharmaraj Aug 24 '21 at 15:16
  • I understand this limitation which is why I set the limit to 999,999. I don't expect the collection to get anywhere near this size. – Andrew Eyesman Aug 24 '21 at 15:18
  • 2
    1) Hotspotting is not about cost, but about limits to scalability. Hence my comment on exact performance requirements. 2) "These ID's must also be short and numeric (ex. 633521)" Why? – Frank van Puffelen Aug 24 '21 at 15:19
  • It's a requirement for the project. We need each user to have a short identifier that can be entered via numpad on a cellphone. – Andrew Eyesman Aug 24 '21 at 15:21
  • 2
    It doesn't sound like they actually need to be sequential. Any random number could be entered by keypad. All you need to do is make sure they're unique. – Doug Stevenson Aug 24 '21 at 15:34
  • So wait, is 1, 2, 3 the same thing as 125463, 493729, 983627? Or does my random number generator satisfy Firestore's scatter algorithm? Maybe I'm just totally misunderstanding the meaning of "sequential." – Andrew Eyesman Aug 24 '21 at 15:48
  • 1
    @AndrewEyesman In the doc you refer to, "sequential IDs" means "monotonically increasing document IDs such as: Customer1, Customer2, Customer3, ...". So 1, 2, 3 is monotonically increasing. A89, A90, A91 is as well. On the other hand 125463, 493729, 983627 **is not**. – Renaud Tarnec Aug 24 '21 at 16:26
  • 1
    Ok I guess that answers my question. So I shouldn't have to worry about anything because my IDs aren't generated sequentially, if I'm understanding correctly. Thank you! – Andrew Eyesman Aug 24 '21 at 16:35

2 Answers2

1

I'm building a Firebase project that requires the use of sequential IDs.

That's a technique widely used in the world of SQL databases. Cloud Firestore is a NoSQL database, and this means that the common SQL techniques, don't apply here.

So most likely you should consider changing the way you store the documents. As you already mentioned, sequential IDs are a performance risk and may lead you to hot-spotting.

It's a requirement for the project. We need each user to have a short identifier that can be entered via Numpad on a cellphone.

So the best recommendation you can get is to go ahead with what the official documentation recommends and not with that requirement that doesn't scale and might create hotspots at some point in time. So it's better if you can adapt your requirements to the techniques that are commended by the Firebase team, so you can make the Firestore Database scale.

As also @FrankvanPuffelen already mentioned in his comment, hot-spotting is not about cost, but about limits to scalability.

This isn't the most elegant solution, but this was the best I could come up with due to Firebase's lack of support for sequential IDs.

It's not about elegancy here, but about techniques that can help you benefit from what Firestore has to offer. And isn't also the lack of support, as it's about the best solutions you can have in order to have the best results.

But after discovering the inherent risk of sequential ID's I'm wondering if this is still a viable solution (or ever was).

No, it's not. I personally recommend against it.

Does this need to be refactored or could I get away with a small performance hit in exchange for functionality?

In my opinion, the way you are creating those IDs overcomplicates your code. To add a document you can simply use set() on document reference or add() on a collection reference and the ID will be created automatically for you.

Edit:

To not confusing future visitors, sequential IDs it the same as consecutive IDs. As also @RenaudTarnec mentioned in his comment, the risk to creating hotspots is if you choose IDs like child1, child2, etc.

If you generate random IDs, then you cannot get that chance, as long as you are sure that your algorithm will generate random unique IDs. However, it's work that should be done by your side. For more info, please also check my answer from the following post:

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • I've edited my answer with some new information, so future visitors will not be confused. – Alex Mamo Aug 25 '21 at 06:55
  • Thank you for the detailed answer, no further explanation needed. I simply confused the word "sequential" with "numeric," a silly mistake while reading the documentation. – Andrew Eyesman Aug 31 '21 at 00:30
0

Random ID can be genereated with Date and 3 Digit Random No to avoid duplication in case of same time multi user engagement

Date.now() + Math.floor(Math.random() * 999)

concat them