ruby-on-rails-3mongodbmongoidmongoid3

Mongodb: Generate an ordering identifier (unique) based on timestamp, similar to BSON id


I have a collection of posts with updated_at timestamps. I want to fetch the documents in batches, sorted by updated_at timestamp (latest first) without using skip (as it slows down with larger values). I could pass the timestamp of the last document of the set to the next query, and use {$lt => last_time_stamp} to fetch the next batch, but there is no guarantee of updated_at being unique (there can be multiple insertions/writes at the same time). Another approach could be that I use $lte and discard repeated entries on client side (again, this could be buggy if the batch size consists of only repeated entries, i.e. all the entries in batch were posted at the same timestamp). Please note that the updated_at timestamp changes on some specific events, so I cannot rely on BSON id for ordering.

How do I ensure that I get (create) a unique identifier as BSON id using the updated_at timestamp, and how to I change it whenever updated_at is changed, so that the order changes. I am using mongoid in a rails app.

Are there any other approaches to achieve this? Currently I query like this:

Post.desc(:updated_at).where(:user => user).where(:updated_at.lt => last_entry_timestamp).limit(10)

Solution

  • You should create an ObjectId from the updated_at time and update it everytime you modify the updated_at time. If you are using Mongoid 3, which now uses Moped as MongoDB driver, you could do something like this:

    Moped::BSON::ObjectId.from_time(Time.new)

    I guess you have already included Mongoid::Timestamps::Updated so at the end you would end up with something similar to:

    UNTESTED CODE

    class MyModel
     include Mongoid::Document
     include Mongoid::Timestamps::Updated 
    
     field :updated_at_id, type: Moped::BSON::ObjectId
    
     set_callback :create, :before, :set_updated_at_id
     set_callback :update, :before, :set_updated_at_id
    
     def set_updated_at_id
       if able_to_set_updated_at?
         self.updated_at_id = Moped::BSON::ObjectId.from_time(Time.now.utc)
       end
     end
    
    end
    

    Moped Documentation for Moped::BSON::ObjectId can be found here

    The code in inspired by Mongoid::Timestamps::Updated source code which can be found here