npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mongoose-generate-unique-key

v0.1.2

Published

Use small random document ids, avoid collisions by checking

Downloads

11

Readme

mongoose-generate-unique-key

Motivation

We often want short readable unique keys for our documents. ObjectIds are too long and ugly.

nanoid addresses this problem quite well, but it still generates longer ids than we really need. With the nanoid approach, you must make your key size large enough that a collision with the existing set of ids will be astronomically unlikely.

Our solution

  • Generate a random id, but even smaller than a nanoid.
  • Check if there is a collision, and if there is, try again.

With this approach, our key size only needs to be around twice as large as than the maximum number of unique keys we want to generate. (Even with a 50% chance of each tested key colliding, it won't take long to find an unused key. But do check the caveats below.)

Usage

const schema = new Schema({
  _id: { type: Number },
  // ...
});

userSchema.plugin(generateUniqueKey(() => String(Math.floor(Math.random() * 1000000))));

If no field is specified, the _id field is assumed. But you can specify a field name if you want to:

userSchema.plugin('userKey', generateUniqueKey(() => String(Math.floor(Math.random() * 1000000))));

Of course it is recommended that you index the field.

What is the down side?

  • When you create a document, you cannot use its _id yet. You need to save it, and then check what _id was generated for that document.

Caveats

  1. Our collision check is asynchronous, performed before the save happens. If you are often saving multiple documents to the DB in parallel, there is a small risk that two documents will generate the exact same unused id at the same time.

    To avoid that, we recommend you set your key size to 100 times the maximum number of ids you will generate. (We should do a more detailed check on this math later. It's the birthday problem, but only 1-1, not 1-set like nanoid.)

  2. If you are saving a lot of documents every second, then you might want to avoid the multiple queries needed to find an unused key. In that case, setting the key size to 100 times the maximum will also help reduce the number of checks made.

    That said, if you are saving a lot of documents in parallel every second, then you should probably be more concerned about DB performance than key size. In that case, we recommend using nanoid, or good old ObjectIds.

  3. If you are generating random ids because you don't want your ids to be predictable, then bear in mind that choosing a smaller key size means attackers will be able to discover your document ids, even if they cannot predict them.

TODO

  • Offer some common key generating routines
  • Offer a recommendedKeySize calculator that can be used directly from the code
  • Warn if the field is not indexed

Alternatives

Instead of generating random ids, it might be simpler to simply opt for auto-incrementing ids.

  • mongoose-auto-increment can do that for you. By using an atomic $inc on a single document, collisions should never happen.