![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
= mongo_odm
Flexible persistence module for any Ruby class to MongoDB.
= Why another ODM for MongoDB?
= Basics
Other Mongo ODMs don't require to explicitly define the possible schema of a model. I think this is necessary to help with type conversions (instanciate the right class for each attribute, and convert them to a Mongo compatible type when persisted). But it's also possible to fill attributes with valid Mongo values without defining them as fields, and only the attributes whose values are different than the default values are stored as part of the document when saved.
A piece of code is better than a hundred of words:
MongoODM.config = {:host => 'localhost', :port => 27017, :database => "my_tests"}
class Shape include MongoODM::Document field :name field :x, Float, :default => 0.0 field :y, Float, :default => 0.0 end
shape = Shape.new(:name => "Point", :x => 0, :y => 5) shape.save
class Circle < Shape # This items are stored on the 'shapes' collection field :radius, Float, :default => 1.0 end
circle = Circle.new.save
all_shapes = Shape.find # Returns a criteria object. It will execute the query and instance the objects once you iterate over it
all_shapes.to_a
In fact, you can instanciate any document stored as a hash to the appropiate class. The document just need to have the attribute "_class" set to the name of the class you want to use as the object type. Example:
MongoODM.instanciate({ :x => 12, :y => 5, '_class' => 'Circle' })
And because any query method returns a MongoODM::Criteria object, you can concatenate them to nest several conditions (like if they were ActiveRecord scopes):
Shape.find(:radius => 1).find({}, {:sort => [:color, :asc]}) # Returns a criteria object. Once you iterate over it, it will run a query with both the :radius selector and :sort order.
You can also define your own class methods that returns criteria objects, and concatenate them to obtain a single criteria with all the conditions merged in the calls order:
class Shape include MongoODM::Document
def self.with_radius(n)
find(:radius => n)
end
def self.ordered_by_color
find({}, {:sort => [:color, :asc]})
end
end
Shape.with_radius(1).ordered_by_color # Returns the same criteria than the previous example
Default values for fields can be either a fixed value, or a block, in which case the block will be called each time an object is instantiated. Example:
class Timestamp include MongoODM::Document
field :value, Time, :default => lambda { Time.now }
field :set, Set, :default => lambda { Set.new }
end
Take a look at the Mongo Ruby driver documentation for the 'find' method to see the available options:
http://api.mongodb.org/ruby/1.2.4/Mongo/Collection.html#find-instance_method
= Collections
By default, mongo_odm stores data on a collection with the same name than the class, pluralized. In case of class inheritance, it uses the name of the parent class. You can override this behavior by setting a different collection for a class:
class Shape set_collection 'my_shapes' end
Alternatively, you can pass a MongoODM::Collection instance to set_collection, to indicate not only a collection name, but also a different connection and/or database:
class Shape set_collection MongoODM::Collection.new(MongoODM.connection.db('another_database'), 'my_shapes') end
= References
You can use BSON::DBRef as the type of a field. This acts as a pointer to any other document in your database, at any collection. If you assign a MongoODM::Document instance to a BSON::DBRef field, it will be converted to a reference automatically. To instantiate any reference object, just call "dereference" on it. To convert any MongoODM::Document object to a reference, just call "to_dbref" on it.
You can even dereference a full array or hash that contains BSON::DBRef instances! It will dereference them at any level.
class Node include MongoODM::Document field :name field :parent, BSON::DBRef field :children, Array end
root_node = Node.new(:name => 'root') root_node.save children1 = Node.new(:name => 'children1', :parent => root_node) children1.save root_node.children = [children1.to_dbref] root_node.save
children1.parent # Returns BSON::DBRef(namespace:"nodes", id: "4d60e8c83f5f19cf08000001") root_node.children # Returns [BSON::DBRef(namespace:"nodes", id: "4d60e8c83f5f19cf08000002")]
children1.parent.dereference # Returns #<Node _id: BSON::ObjectId('4d60e8c83f5f19cf08000001'), children: [BSON::DBRef(namespace:"nodes", id: "4d60e8c83f5f19cf08000002")], name: "root", parent: nil>
root_node.children.dereference # Returns [#<Node _id: BSON::ObjectId('4d60e8c83f5f19cf08000002'), children: nil, name: "children1", parent: BSON::DBRef(namespace:"nodes", id: "4d60e8c83f5f19cf08000001")>]
= Associations
To embed just one copy of another class, just define the field type of that class. The class just need to respond to the "type_cast" class method and the "to_mongo" instance method. Example:
class RGB def initialize(r, g, b) @r, @g, @b = r, g, b end
def inspect
"RGB(#{@r},#{@g},#{@b})"
end
def to_mongo
[@r, @g, @b]
end
def self.type_cast(value)
return nil if value.nil?
return value if value.is_a?(RGB)
return new(value[0], value[1], value[2]) if value.is_a?(Array)
end
end
class Color include MongoODM::Document field :name field :rgb, RGB
index :name, :unique => true
end
Color.create_indexes # You can also use MongoODM.create_indexes to create all the indexes at all classes at the same time
color = Color.new(:name => "red", :rgb => RGB.new(255,0,0)) color.save
red = Color.find({:name => "red"}).first
Of course, if the embedded object's class includes the MongoODM::Document module, you don't need to define those methods. Just define the field as that class:
class RGB include MongoODM::Document field :r, Fixnum field :g, Fixnum field :b, Fixnum end
class Color include MongoODM::Document field :name field :rgb, RGB end
color = Color.new(:name => "red", :rgb => RGB.new(:r => 255, :g => 0, :b => 0)) color.save
red = Color.find({:name => "red"}).first
If you want to save a collection of objects, just define the field as an Array. You can even store objects of different types!
class Shape include MongoODM::Document field :x, Float field :y, Float end
class Circle < Shape include MongoODM::Document field :radius, Float end
class Line < Shape include MongoODM::Document field :dx, Float field :dy, Float end
class Draw include MongoODM::Document field :objects, Array end
circle1 = Circle.new(:x => 1, :y => 1, :radius => 10) circle2 = Circle.new(:x => 2, :y => 2, :radius => 20) line = Line.new(:x => 0, :y => 0, :dx => 10, :dy => 5)
draw = Draw.new(:objects => [circle1, line, circle2]) draw.save
Draw.find_one
To reference the associated objects instead of embed them, you can use BSON::DBRef (to reference one), Array (to reference several), and others:
class Flag include MongoODM::Document field :colors_refs, Array, :default => []
def add_color(color)
colors_refs << color.to_dbref
end
def colors
colors_refs.dereference
end
end
class Color include MongoODM::Document field :name end
color_red = Color.new(:name => "red") color_red.save color_green = Color.new(:name => "green") color_green.save
flag = Flag.new flag.add_color(color_red) flag.add_color(color_green) flag.save
flag.colors # Returns [#<Color _id: BSON::ObjectId('4d60ea4e3f5f19cf10000001'), name: "red">, #<Color _id: BSON::ObjectId('4d60ea4e3f5f19cf10000002'), name: "green">]
flag.colors
flag.colors.to_a
Or you can build your custon methods. Example:
class Flag include MongoODM::Document field :colors_ids, Array
def colors
Color.find(:_id => {'$in' => colors_ids})
end
end
class Color include MongoODM::Document field :name end
Color.new(:name => "red").save Color.new(:name => "green").save
flag = Flag.new(:colors_ids => [ Color.find_one(:name => "red").id, Color.find_one(:name => "green").id ]) flag.save
flag.colors
flag.colors.to_a
= Callbacks
For now, the available callbacks are: after_initialize, before_save, after_save
Example:
class User include MongoODM::Document
field :encrypted_password
attr_accessor :password
before_save :encrypt_password
def encrypt_password
return if self.password.blank?
self.encrypted_password = encrypt(password)
end
protected :encrypt_password
end
= Validations
All the validation methods defined in ActiveModel::Validations are included
Example:
class User include MongoODM::Document field :email
validates_presence_of :email
validates_uniqueness_of :email, :case_sensitive => false
validates_format_of :email, :with => /^([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/
end
= Dirty
All the dirty object methods defined in ActiveModel::Dirty are included
Example:
class User include MongoODM::Document field :email end
user = User.new user.email = "hello@h1labs.com" user.email_changed? # Returns true user.email_change # Returns [nil, "hello@h1labs.com"] user.changes # Returns {"email" => [nil, "hello@h1labs.com"]}
= Others
Access to a cursor to the whole collection:
User.cursor
Use cursor methods directly on the class:
User.has_next? User.each{...} User.next_document User.rewind! ...
= TODO
= More
For now, take a look at the Mongo Ruby driver syntax:
http://api.mongodb.org/ruby/1.2.4/index.html
= Credits
Carlos Paramio, http://h1labs.com.
See CONTRIBUTORS file for a list of contributions.
= License
See LICENSE file for details.
FAQs
Unknown package
We found that mongo_odm demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.