Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can one shorten mongo ids for better use in URLs?

Tags:

python

mongodb

I've built a number of python driven sites that utilize mongodb as a database backend and am very happy with it's ObjectId system, however, I'd love to be able encode the ids in a shorter fashion without building a mapping collection or utilizing a url-shortener service.

Suggestions? Success stories?

like image 690
jcinis Avatar asked Nov 23 '10 21:11

jcinis


2 Answers

You could compress them as Base62 numbers. This doesn't save a lot of space, but it does save you a few bytes per ID. My example's Ruby, but similar usage in Python wouldn't be hard.

ree-1.8.7-2010.02 > User.first._id.to_s
 => "4c76f3dd98db74697500003b"

ree-1.8.7-2010.02 > User.first._id.to_s.to_i(16).base62_encode
 => "uMarF7LmpY3bNOSn"
like image 168
Chris Heald Avatar answered Sep 20 '22 18:09

Chris Heald


Heh, I recently wanted the exact same thing myself.

What I've ended up doing is giving every document that needs one a "public id" that is unique (like the ObjectId), but that is just an auto-incrementing number (so it'll take a while before the numbers get huge, and even longer if they're hex-encoded). This way, I can use the ObjectId internally (which I suspect is faster), and lookup externally referenced documents using their public id.

Note that there is a little performance hit when creating these public ids since each one requires an atomic update to a document (so you should only use them where you need them).

The key to creating an auto-incrementing number is MongoDB's findAndModify command to both increment a value and return the old value in a single atomic operation.

Since you're using Python, and so am I, here is the code that I'm currently using (note that it's not in production yet):

from pymongo import Connection
from pymongo.son import SON

db = Connection().mydatabase

PUBLIC_ID_COLLECTION = 'next_public_id'
def next_public_id():
    result = db.command(SON({ 'findandmodify': PUBLIC_ID_COLLECTION },
        query = { '_id': 'manager' },
        update = { '$inc': { 'next_public_id': 1 } },
        upsert = True       # Insert if not already existing
    ))
    manager = result['value']
    return manager.get('next_public_id', 0)
like image 29
Cameron Avatar answered Sep 17 '22 18:09

Cameron