Join an array of mongoid docs with target objects by specified relation and delegation fields
Add this line to your application's Gemfile:
gem 'join_collection'
And then execute:
$ bundle
Or install it yourself as:
$ gem install join_collection
The class JoinCollection itself is a wrapper around an array of mongoid docs, so to initialize it, simply put
user_collection = JoinCollection.new(users) # where users is an array of mongoid docs
We will call what we put inside the initilizer the source objects.
To use any of the join_*
functions, make sure you provide the following parameters.
- The 1st parameter is the
target_name
, which is used as the prefix for the delegation fields. - The 2nd parameter is the
target_class
, which is used to query target objects. - The 3rd parameter is the
options
, which is not optional and it must be a hash containing a:relation
key and a:delegation
key.
- The key
:relation
points to another hash, which specifies the foreign key to primary key for the type of join relation. - The key
:delegation
also points to a hash, which specifies the:fields
of the target object to be delegated to the doc in the source objects. In a has_many relation, you can also privide a:if
conditional block to specify which target object to delegate if there are many target objects.
Assume we have a user belongs_to site
relationship, and the Site class has the field url
.
user_collection = JoinCollection.new(users)
user_collection.join_to(:site, Site, :relation => {:site_id => :id}, :delegation => {:fields => [:url]})
After this, all the source objects, the users, in the user_collection will have the field site_url
user_collection.source_objects.first.site_url # => "http://..."
Assume we have a user has_one profile
relationship, and the Profile class has the field twitter
.
user_collection = JoinCollection.new(users)
user_collection.join_one(:profile, Profile, :relation => {:user_id => :id}, :delegation => {:fields => [:twitter]})
After this, all the source objects, the users, in the user_collection will have the field profile_twitter
user_collection.source_objects.first.profile_twitter # => "https://twitter.com/..."
Assume we have a user has_many contacts
relationship, and the Contact class has the field phone
.
user_collection = JoinCollection.new(users)
user_collection.join_many(:contacts, Contact, :relation => {:user_id => :id},
:delegation => {:if => lambda { |x| x.is_active? }, :fields => [:phone]})
After this, all the source objects, the users, in the user_collection will have the field contact_phone
user_collection.source_objects.first.contact_phone # => "0987-654-321"
If you specify a delegation field which is identical to the target name of that join type, the whole object(s) will be captured.
user_collection.join_to(:site, Site, :relation => {:site_id => :id}, :delegation => {:fields => [:site]})
user_collection.source_objects.first.site # get the site the user belongs to
user_collection.join_one(:profile, Profile, :relation => {:user_id => :id}, :delegation => {:fields => [:profile]})
user_collection.source_objects.first.profile # get the profile the user has
user_collection.join_many(:contacts, Contact, :relation => {:user_id => :id}, :delegation => {:fields => [:contacts]})
user_collection.source_objects.first.contacts # get all contacts the user has
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request