ruby-on-railsrubyneo4jneo4jrb

Neo4j eager load ActiveRel


I'm tryin to get specific keywords that MAY be related ONLY to specific users and the return the relationships.

Keyword.where(text: ['key1', 'key2'])
  .tagged_users(:u, :rel)
  .where(uid: [100, 101])
  .pluck(:rel).each_with_object({}) do |rel, obj|
      uid     = rel.to_node.uid
      keyword = rel.from_node.text
      obj[uid] ? obj[uid] << keyword : obj[uid] = [keyword]
   end

Assuming we have only one relationship with User 100 tagged with Keyword 'key2' the desired result is { 100 => ['key2'] }

The above code works, but for each rel it's performing 2 queries to the db; one for rel.to_node and one for rel.from_node.

I was hoping there is a solution to 'eager load' the rel.from_node and rel.to_node so only one query will be executed for the entire snippet.

(Another solution would be to run for each keyword and getting it's tagged users but this is also requires many queries.)


Solution

  • The solution was to add with_associations so we don't even need the relation object.

    def self.uids_to_keywords(keywords, user_ids)
        Keyword.where(text: keywords).tagged_users.with_associations(:keywords)
            .where(user_id: user_ids).each_with_object({}) do |user, obj|
          obj[user.user_id] = keywords & user.keywords.map(&:text)
        end
    end