4

I am aware of the absence of a constraint for naming relationships, though it is tough to get one guideline and work with it over all the relationships that we might encounter.

Would you go with something like this:

(u:User)-[:LIKES]->(p:Post)
(u:User)-[:LIKES]->(c:Comment)

and then query based on the label; Or something like this:

(u:User)-[:LIKES_POST]->(p:Post)
(u:User)-[:LIKES_COMMENT]->(c:Comment)

Another case is a threaded chat application where a User can start a thread with multiple other users, here's the structure I have in mind:

# the thread
CREATE (ct:ChatThread {created_at: timestamp()})

# the thread starter
(u:User {user: 1})<-[:IN_THREAD {type: 'owner'}]-(ct)

# members of the thread
(u:User {user: 2})<-[:IN_THREAD {type: 'member'}]-(ct)
(u:User {user: 3})<-[:IN_THREAD {type: 'member'}]-(ct)
Chris Martin
  • 30,334
  • 10
  • 78
  • 137
mulkave
  • 831
  • 1
  • 10
  • 22
  • 1
    Wouldn't the being in the thread been inferred from posts and comments? I like the idea of having an explicit thread node and attaching the users, so it becomes easier and faster to query for the members. Would user1 also be a member or only an owner? You could also use THREAD_OWNER and THREAD_MEMBER, and probably have the owner also have a member relationship. – Michael Hunger May 06 '14 at 00:27
  • Dealing with relationships have gotten much clearer after reading the book suggested by David, it turns out that the more relationships you have the better you tackle the business requirements in your application (to a certain extent of course). Also, querying a relationship straight with its name is preferred over querying the same relationship name with the conditions being in the properties of the relationship itself, which totally agrees with your suggestion of adding THREAD_OWNER and THREAD_MEMBER and a MEMBER_OF for all participants. +1 to that! – mulkave May 07 '14 at 10:50
  • Isn't your second version redundant? You can easily check if the `LIKES` relationship is for a post or a comment by looking at the target node's label. So why put that into the relationship type itself? – ADTC May 14 '16 at 18:48

1 Answers1

4

I'll address the first example you posted:

(u:User)-[:LIKES]->(p:Post)
(u:User)-[:LIKES]->(c:Comment)

vs

(u:User)-[:LIKES_POST]->(p:Post)
(u:User)-[:LIKES_COMMENT]->(c:Comment)

This is essentially fine-grain vs. coarse-grain relationship ,as described in the Graph Databases book (ch. 4 - Building a Graph Database Application). Think about your usage:

  • If you always want to query what a user likes, regardless whether it's Post or Comment, then LIKES works great.
  • If you want to search specifically for a user's Posts, or a user's Likes, then fine-grain relationship types such as LIKES_POST work great. If you stayed with the more generic LIKES, you'd need to pay attention to the entity types in your filtering. And... if this list grows over time, you'll need to modify your queries to include the new types (and if this type list is unbounded, it could get a bit cumbersome).
  • If you often mix it up, you may want to consider having both fine- and coarse-grain relationships between these nodes.
David Makogon
  • 69,407
  • 21
  • 141
  • 189
  • Thanks @David Makogon, in my case querying based on Labels is not an issue, I am currently in the course of writing a wrapper for the Neo4j driver so if we take this into consideration from the get go it would be a lot simpler to query both, everything that the user likes and specific user likes. Don't you think ? – mulkave May 01 '14 at 18:57