-
-
Save ahoward/1535180 to your computer and use it in GitHub Desktop.
Integer sequence ids in Mongo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rubygems' | |
require 'mongoid' | |
Mongoid.configure do |config| | |
config.master = Mongo::Connection.new.db("test") | |
end | |
Mongoid.database.add_stored_function 'sequence', <<-__ | |
function(sequence) { | |
var doc = | |
db.sequences.findAndModify({ | |
'query' : {_id : sequence}, | |
'update' : {$inc : {'value' : 1}}, | |
'new' : true, | |
'upsert' : true | |
}); | |
return doc.value; | |
} | |
__ | |
module Mongoid | |
class Sequence | |
include Mongoid::Fields::Serializable | |
def Sequence.for(name) | |
sequence = new | |
sequence.name = name.to_s | |
sequence | |
end | |
attr_accessor(:name) | |
def instantiate(*args) | |
self | |
end | |
def deserialize(object) | |
object.to_i | |
end | |
def serialize(object) | |
case object | |
when false, nil | |
Mongoid.master.eval("sequence('#{ name }')").to_i | |
when BSON::ObjectId | |
object.to_s.to_i(16) | |
when Integer | |
object | |
else | |
Integer(object) | |
end | |
end | |
end | |
module Document | |
module ClassMethods | |
def sequence | |
@sequence ||= Sequence.for(collection.name) | |
end | |
end | |
end | |
end | |
class B | |
include Mongoid::Document | |
end | |
class A | |
include Mongoid::Document | |
A.field(:_type, :type => String, :default => name) | |
A.field(:_id, :type => sequence, :default => nil) | |
if respond_to?(:identity) | |
identity(:type => String, :default => proc{ generate_id }) rescue nil | |
end | |
if respond_to?(:using_object_ids) | |
self.using_object_ids = false | |
end | |
::Mongoid::Identity.class_eval do | |
def generate_id | |
@document.respond_to?(:generate_id) ? @document.generate_id : BSON::ObjectId.new | |
end | |
end | |
def self.generate_id | |
nil | |
end | |
def generate_id | |
self.class.generate_id | |
end | |
end | |
require 'benchmark' | |
B.delete_all | |
A.delete_all | |
n = 10_000 | |
Benchmark.bm do |bm| | |
bm.report('B'){ n.times{ B.create } } | |
bm.report('A'){ n.times{ A.create } } | |
end | |
__END__ | |
user system total real | |
B 2.450000 0.140000 2.590000 ( 2.595748) | |
A 4.320000 0.460000 4.780000 ( 8.151828) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment