Should i store hashids in database or decode them on every request?

Published 2 years ago by mtvs_dev

I`m going to use hashids instead of database ids in my urls, should I dedicate a field to them in database table or encode ids to hashids on url generation and decode hashids to ids on incoming requests?

Best Answer (As Selected By mtvs_dev)
ivanakimov

Hey guys,

Hashids creator here. Wanted to weigh in on a few points:

  • Ids generated by Hashids are unique. You are not required to check for that.
  • Minimum length parameter (usually 2nd parameter to the constructor) works like padding. If you set it to 5, that only means that if your generated id is shorter than 5 chars, it'll be padded to 5 characters. Ids grow in length as numbers increase and there is no limit on how long they get.
  • Finally, database vs on-the-fly -- pick the best method for you. In my own projects I usually do it on the fly for one simple reason. Numbers I encode are usually primary ids of the table (which are always indexed), so it's very fast to decode on the fly and select by them. If you create a separate column for slugs, you'd probably want to put an index on it so selects are fast and that means more unnecessary indices for your database to manage on that table. This is of course specific to RDBMS and the way you use these slugs.
mstnorris

If you store them in the database you can check for uniqueness too.

Hashids suggests creating lots of IDs before you use it in production to ensure that you don't get duplicates for your use case.

pmall
pmall
2 years ago (547,945 XP)

You can treat hashids like slugs

mtvs_dev

@pmall Initially I was going to do it like you said but I saw this answer http://stackoverflow.com/a/12257207/1404348

The good thing about this is you don't even have to store these hashes in the database. You could get the hash from url once request comes in and decrypt it on the fly - and then pull by primary id's from the database (which is obviously an advantage in speed).

So still not sure which way i should do this.

mtvs_dev

@mstnorris hashids are unique

mstnorris

@mtvs_dev not necessarily. You can't count on it. for example, you could have a very small alphabet, lets use HEX, and only a hashid length of 5.

That would be 16^5 = 1048576 possibilities, which means that you'd run out of entities just after 1 million records.

So no they are not guaranteed to be unique.

mtvs_dev

@mstnorris Not true about hashids.org

Hashids is a small open-source library that generates short, unique, non-sequential ids from numbers.

gregrobson

Just to add to what @mstnorris said.

Hash ids are unique so long as the alphabet and hash id length are long enough to allow a suitable number of permutations. From the docs:

There are no collisions because the method is based on integer to hex conversion.

mstnorris

@mtvs_dev honestly, read the docs. As I've explained above, and as @gregrobson has also corroborated, they are only unique if your alphabet and length allows them to be.

If you really want them to be unique, then look at something like UUIDs. Webpatser has a good Laravel package.

mtvs_dev

@gregrobson @mstnorris ok, thanks for telling me about this issue

pmall
pmall
2 years ago (547,945 XP)

@mtvs_dev whatever it is up to your taste is you want to store hashids or decode them on the fly. From my experience I think it will be easier to store them. And what if you want to check something in your database manually, you have to encode the id before manually firing sql queries, which is cumbersome.

ivanakimov

Hey guys,

Hashids creator here. Wanted to weigh in on a few points:

  • Ids generated by Hashids are unique. You are not required to check for that.
  • Minimum length parameter (usually 2nd parameter to the constructor) works like padding. If you set it to 5, that only means that if your generated id is shorter than 5 chars, it'll be padded to 5 characters. Ids grow in length as numbers increase and there is no limit on how long they get.
  • Finally, database vs on-the-fly -- pick the best method for you. In my own projects I usually do it on the fly for one simple reason. Numbers I encode are usually primary ids of the table (which are always indexed), so it's very fast to decode on the fly and select by them. If you create a separate column for slugs, you'd probably want to put an index on it so selects are fast and that means more unnecessary indices for your database to manage on that table. This is of course specific to RDBMS and the way you use these slugs.
mstnorris

Ahh I wasn't aware that IDs grow in length, I thought you set the length and it was set in stone. That isn't clear in the docs.

mikebarwick

I encode and decode hashids based off the ID on the fly, as below. Super simple!

https://github.com/vinkla/hashids

Then in whatever model I want to hash the ID for, I add this method. Note, hashed ID will be returned in a collection, etc:

/**
 * Get the value of the model's route key.
 *
 * @return mixed
 */
public function getRouteKey()
{
    return Hashids::encode($this->getKey());
}

Then in my routes files, I added this to decode incoming requests:

/*
|---------------------------------------------------
| Decode all hashed IDs before passing to controller
|---------------------------------------------------
*/
Route::bind('id', function ($id, $route) {
    return Hashids::decode($id)[0];
});

Example route. The bind method above looks for ANY route URL that contains id. You can change above if your naming convention is different.

Route::get('task/{id}', ['as' => 'task.show', 'uses' => 'TaskController@show']);
balping
balping
1 year ago (51,820 XP)

Here's another package specifically for routing: https://github.com/balping/laravel-hashslug

It works with implicit route model binding automatically. All you need to do is add a trait and typehint in controller:

class Post extends Model {
    use HasHashSlug;
}
// routes/web.php
Route::resource('/posts', 'PostController');
// app/Http/Controllers/PostController.php

public function show(Post $post){
  return view('post.show', compact('post'));
}

Please sign in or create an account to participate in this conversation.