33

This might sound like a trivial question, but it is rather important for consumer facing apps

What is the easiest way and most scalable way to map the scary mongo id onto a id that is friendly?

xx.com/posts/4d371056183b5e09b20001f9

TO

xx.com/posts/a

M

Community
  • 1
  • 1
meow
  • 27,476
  • 33
  • 116
  • 177
  • 1
    You can refer to this post at Google Group: http://groups.google.com/group/mongoid/browse_thread/thread/b4edab1801ac75be/c810df90bb3a2145?lnk=gst&q=incremental#c810df90bb3a2145 Even though it doesn't actually answer your question, it gives you some alternatives to solve the problem. – siong1987 Jan 20 '11 at 21:17

4 Answers4

27

You can create a composite key in mongoid to replace the default id using the key macro:

class Person
  include Mongoid::Document
  field :first_name
  field :last_name
  key :first_name, :last_name
end

person = Person.new(:first_name => "Syd", :last_name => "Vicious")
person.id # returns "syd-vicious"

If you don't like this way to do it, check this gem: https://github.com/hakanensari/mongoid-slug

Community
  • 1
  • 1
kerberoS
  • 271
  • 2
  • 2
21

Define a friendly unique field (like a slug) on your collection, index it, on your model, define to_param to return it:

def to_param
  slug
end

Then in your finders, find by slug rather than ID:

@post = Post.where(:slug => params[:id].to_s).first

This will let you treat slugs as your effective PK for the purposes of resource interaction, and they're a lot prettier.

Chris Heald
  • 61,439
  • 10
  • 123
  • 137
  • 4
    Why not even use the slug for the `_id` field? If it's going to be unique and indexed, there's no need to have both. `_id` isn't limited to the `ObjectId` type. – Theo Jan 21 '11 at 18:32
  • 4
    I think because mongodb convention is to have real objectids in the _id field. for example, mongoid used string ids for a while http://www.mongodb.org/pages/viewpage.action?pageId=16646831 and it caused issues – Scott Schulthess Jan 25 '11 at 15:43
  • what about efficiency? wouldn't searching for long string slug take longer than searching by id? – eagor Oct 24 '14 at 13:33
  • 2
    @eagor If you are searching on a field, you should index that field. At that point, it should approximately about as expensive as searching for a document with a given ID. – Chris Heald Oct 24 '14 at 18:41
8

Unfortunately, the key macro has been removed from mongo. For custom ids, users must now override the _id field.

class Band
  include Mongoid::Document
  field :_id, type: String, default: ->{ name }
end
styliii
  • 646
  • 6
  • 13
  • This has a number of gotchas. If you do not set the `name` when instantiating the object (Band.new) you will end up with a nil `_id`. Setting the `_id` afterwards does not work. – Mohamad Feb 06 '14 at 18:30
4

Here's a great gem that I've been using to successfully answer this problem: Mongoid-Slug

https://github.com/digitalplaywright/mongoid-slug.

It provides a nice interface for adding this feature across multiple models. If you'd rather roll your own, at least check out their implementation for some ideas. If you're going this route, look into the Stringex gem, https://github.com/rsl/stringex, and acts_as_url library within. That will help you get the nice dash-between-url slugs.

Glenn
  • 1,092
  • 1
  • 10
  • 22