MongoId y Rails3

by Gastón Ramos

Bueno últimamente vengo posteando con bastante delay (espero que eso cambie),
en esta ocasión voy a hacer un pequeño post acerca de mis experiencias migrando
una app de rails 2.3.4 y Active record con Mysql a Rails3, MongoId y Ruby 1.9.1,
sí, así completita la cosa, la aplicación no es demasiado grande así que viene bien
para probar esta nueva arquitectura.
No voy entrar en los detalles de como instalar rails3 y esas cosas por que ya existen
varios posts acerca del tema y no me quiero repetir, pasemos derecho al tema mongoid
Mongoid es un ODM(Object-Document-Mapper) para mongoDB, tiene varias cosas buenas algunas de las que me llamaron
la atención a mí es que no necesitamos migrations para para modificar nuestros documentos
(en sql diríamos tablas) además los campos (columnas) los podemos ver directamente abriendo
el modelo.


class Order
  include Mongoid::Document
  include Mongoid::Timestamps
  include Mongoid::XmlBuilder

  field :external_id, :type => Integer
  field :account_id, :type => Integer
  field :order_type, :type => String
  field :posted, :type => Boolean
  field :send_result_notification, :type => Boolean
  field :file_duration_ms, :type => Integer
  field :created_at, :type => DateTime
  field :updated_at, :type => DateTime

  embeds_one :result, :class_name => "OrderResult"

  #  -----------------------------------------------------------------------------------------------
  #  Viejo named_scope reemplazado por mongoid queries
  #
  #  named_scope :pendings, :conditions => "NOT EXISTS (SELECT * FROM
  #   order_results WHERE
  #    order.id = order_results.transcription_id)
  #    AND posted_id IS NOT NULL AND
  #    orders.posted = 1"
  #
  # ------------------------------------------------------------------------------------------------

  def self.without_results
    result_ids = TranscriptionResult.criteria.only(:id).map{|id| }
    Order.where(:_id.nin => result_ids)
  end

  def self.pendings
    without_results.where(:posted => true)
  end
end

Otra de las ventajas es que los criterios son anidables con lo cual funcionarían
como una especie de scope de Active Record, fijensé como quedó el viejo named_scope
con mongoid, mucho más claro que antes para mi gusto.
Otra de las ventajas de mongoID en particular es que incluye ActiveModel, con lo
cual tenemos las mismas validaciones que en Rails, también podemos definir callbacks de forma similar que en Active Record.

Pasemos a explicar un poquito:
Lo que yo necesito son los transcriptions que no tengan un transcription_result asociado y dónde posted sea true.


result_ids =OrderResult.criteria.only(:id)
= > #[:id]}, @klass=OrderResult, @documents=[]>


con esto saco la lista de results, sólo me traigo los ids por que no necesito
otra cosa y le aplico un map para obtener una array con la lista de ids (cómo pueden ver eso devuelve un objeto Mongoid::Criteria) con esto ya tengo los transcriptions que no tienen results (el método without_results). Después una vez que tengo esto ya es más fácil
generar los pendings (transcriptions sin results y con posted == true).
Nota: :_id.nin quiere decir “los _id que no estén incluidos en (not included in)”
para más detalles pueden ver la doc de queries de mongoid

PD: MongoId también tiene named_scopes dejo pendiente para el próximo refactoring pasar esto a named_scope de mongoid.

Nos vemos en el próximo post.