I've been hearing lately that some many-to-many and one-to-many relationships (without additional join data, eg user-membership-group) can be queried significantly faster in Postgres using array columns of id's rather than join tables see discussion for Node Postgres ORM.
For a many-to-many relationship, choosing which table (or both) to maintain the relationship arrays would depend on which direction the query goes (users<->groups would need array columns on both tables, users->tag would only require the relationship to be maintained in an array column on the users table only.
Several questions:
many-to-many relationships? ```
module ArrayRelationships
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
# association must be lower case, pluralized name of associated class
def array_has_many(association)
define_method(association) do
instance_name = association.singularize
class_name = instance_name.titleize
class_name.constantize.where(id: self.send("#{instance_name}_ids"))
end
end
end
end
class User << ActiveRecord::Base
include ArrayRelationships
array_has_many :tags
end
Of course, the users table would have to have the :tag_ids array field in the database. If we wanted to add the inverse relationship for Tag#users, we would simply add the db field, include ArrayRelationships, and array_has_many :users.
EDITOR: On the page of this gem it says, use it on your own risk
WARNING: This gem is a work in progress and hasn't released yet.
I haven't tried it yet, but appears that someone built a gem to support arrays for associations: https://github.com/marshall-lee/has_array_of. Copying from the README:
Suppose we have a playlist that contains many videos. One video can be included in many playlists. It's a classic many-to-many situation but we implement it differently.
# db/migrate/20141027125227_create_playlist.rb
class CreatePlaylist < ActiveRecord::Migration
def change
create_table :playlists do |t|
t.integer :video_ids, array: true # adding array fields works only starting from Rails 4
t.index :video_ids, using: :gin # we add GIN index to speed up specific queries on array
end
end
end
# app/models/playlist.rb
class Playlist < ActiveRecord::Base
has_array_of :videos # by convention, it assumes that Post has a video_ids array field
end
# app/models/video.rb
class Video < ActiveRecord::Base
belongs_to_array_in_many :playlists # optional
end
Now we can work with videos like with regular array. It will correctly proxy all changes to video_ids field.
playlist = Playlist.find(1)
playlist.videos = [video1,video2] # playlist.video_ids = [1, 2]
playlist.videos[0] = video3 # playlist.video_ids[0] = 3
playlist.videos.insert(1, video4) # playlist.video_ids = [3, 4, 2]
playlist.videos.delete_at(1) # playlist.video_ids = [3, 2]
playlist.videos.pop # playlist.video_ids = [3]
# ... and so on
video3.playlists
# => [playlist]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With