Relating an entity to a relationship proper in Neo4j?

后端 未结 2 633
盖世英雄少女心
盖世英雄少女心 2021-01-21 12:42

I\'m attempting to use Neo4j to model the relationship between projects, staff, and project roles. Each project has a role called \"project manager\" and a role called \"direct

相关标签:
2条回答
  • 2021-01-21 13:25

    @wassgren's answer is a solid one, worth considering.

    I'll offer one additional option. That is, you can "Reify" that relationship. Reificiation is sort of when you take a relationship and turn it into a node. You're taking an abstract association (relationship between staff and project) and your'e turning it into a concrete entity (a Role) All of the other answer options involve basically two nodes Project and Staff, with variations on relationships between them. These approaches do not reify role, but store it as a property, or a label, of a relationship.

    (director:Staff {name: "Joe"})-[:plays]->(r:Role {label:"Director"})-[:member_of]->(p:Project { name: "Project X"});
    

    So...people don't contribute to projects directly, roles do. And people play roles. Which makes an intuitive sense.

    The advantages of this approach is that you get to treat the "Role" as a first-class citizen, and assert relationships and properties about it. If you don't split the "Role" out into a separate node, you won't be able to hang relationships off of the node. Further, if you add extra properties to a relationship that is masquerading as a role, you might end up with confusions about when a property applies to the role, and when it applies to the association between a staff member and a project.

    Want to know who is on a project? That's just:

      MATCH (p:Project {label: "Project X"})<-[:member_of]-(r:Role)<-[:plays]-(s:Staff)
       RETURN s;
    

    So I think what I'm suggesting is more flexible for the long term, but it might also be overkill for you.

    Consider a hypothetical future requirement: we want to associate roles with a technical level or job category. I.e. the project manager should always be a VP or higher (silly example). If your role is a relationship, you can't do that. If your role is a proper node, you can.

    0 讨论(0)
  • 2021-01-21 13:36

    Conceptually, a Neo4j graph is built based on two main types - nodes and relationships. Nodes can be connected with relationships. However, both nodes and relationships can have properties.

    To connect the Project and Staff nodes, the following Cypher statement can be used:

    CREATE (p:Project {name:"Project X"})-[:IS_DIRECTOR]->(director:Staff {firstName:"Jane"})
    

    This creates two nodes. The project node has a Label of type Project and the staff node has a Label of type Staff. Between these node there is a relationhip of type IS_DIRECTOR which indicates that Jane is the director of the project. Note that a relationship is always directed.

    So, to find all directors of all project the following can be used:

    MATCH (p:Project)-[:IS_DIRECTOR]->(director:Staff) RETURN director
    

    The other approach is to add properties to a more general relationship type:

    create (p:Project {name:"Project X"})<-[:MEMBER_OF {role:"Director"}]-(director:Staff {firstName:"Jane"})
    

    This shows how you can add properties to a relationship. Notice that the direction of the relationship was changed for the second example.

    To find all directors using the property based relationship the following can be used:

    MATCH (p:Project)<-[:MEMBER_OF {role:"Director"}]-(directors:Staff) RETURN directors
    

    To retrieve all role types (e.g. director) the following can be used:

    MATCH 
        (p:Project)-[r]->(s:Staff) 
    RETURN 
        r,       // The actual relationship 
        type(r), // The relationship type e.g. IS_DIRECTOR
        r.role   // If properties are available they can be accessed like this
    

    And, to get a unique list of role names COLLECT and DISTINCT can be used:

    MATCH 
        (p:Project)-[r]->(s:Staff) 
    RETURN 
        COLLECT(DISTINCT type(r)) // Distinct types
    

    Or, for properties on the relationship:

    MATCH 
        (p:Project)-[r]->(s:Staff) 
    RETURN 
        COLLECT(DISTINCT r.role) // The "role" property if that is used
    

    The COLLECT returns a list result and the DISTINCT keyword makes sure that there are no duplicates in the list.

    0 讨论(0)
提交回复
热议问题