user2172335
user2172335

Reputation: 111

Searching nth-level friends in neo4j.rb in bi-directional relationship graph

I have a User class defined as below

class User
  include Neo4j::ActiveNode
  include Neo4j::Timestamps
  property :user_id, type: Integer, constraint: :unique
  property :max_friends_count, type: Integer, default: 5
  validates :user_id, :presence => true
  has_many :out, :followings, model_class: :GraphUser, rel_class: :GraphRel, unique: true
  has_many :in, :followers, model_class: :GraphUser, rel_class: :GraphRel, unique: true
end

I have created user1 and user2 with user_id 1 and 2 respectively.

And then I dis search followings of followings using user1.followings(rel_length: 2). But the result come out as user1 itself because both user1 and user2 are following each other.

I have tried order(:breadth_first) and other methods to exclude the nodes that have already been visited. I might not have done enough research but does anyone have any idea how to do this?

Upvotes: 1

Views: 85

Answers (1)

Brian Underwood
Brian Underwood

Reputation: 10856

Firstly, you might want to use the id_property. If you use a property for user_id and set constraint: :unique you'll still have the automatically generated uuid property. That may be what you want, but just a heads up. Here's the documentation for id_property:

https://github.com/neo4jrb/neo4j/wiki/Neo4j-v3-Unique-IDs

To your question, your code generates Cypher similar to this (I needed to change the model_class and rel_class options):

MATCH user15573
WHERE (ID(user15573) = {ID_user15573})
MATCH user15573-[rel1:`FOLLOWS`*2]->(result_followings:`User`)

In a single MATCH clause in Cypher, Neo4j will make sure that the same relationship isn't traversed more than once for a single path traversal. But as you said if they are following each other that means that it can follow the other relationship to go back to the original user. In that can you'd need to exclude the original user from the potential results:

MATCH user15573
WHERE (ID(user15573) = {ID_user15573})
MATCH user15573-[rel1:`FOLLOWS`*2]->(result_followings:`User`)
WHERE result_followings <> user15573

In Ruby this would be:

user1.as(:source).followings(:target, nil, rel_length: 2).where('source <> target')

Upvotes: 1

Related Questions