"Ordered lists" and bi- vs. uni-directional relationships - neo4j

I'm a Neo4j newbie, just playing around in the browser modelling data for a project at the moment.
Here's my use case: A user can have a bunch of items. Each item is described by a storyline.
(:User)-[:OWNS]->(:Item)<-[:DESCRIBES]-(:Storyline)
No issues so far. However, the storyline needs to contain "cards", basically chapters of the story that need to be in order. So, my first thought was this.
(:Storyline)<-[:FOLLOWS]<-(a:Card)<-[:FOLLOWS]-(b:Card)
However, if we start at Card B, we now have to follow the path back to see what storyline/item the card belongs to. Seems inefficient. Would it be better to do this?
(a:Card {order: 0})-[:BELONGS_TO]->(:Storyline)
(b:Card {order: 1})-[:BELONGS_TO]->(:Storyline)
Or, might I even trash the Storyline and just have the following?
(:Card {order:0})-[:DESCRIBES]->(:Item)
Next, a user should be free to create a link to another storyline card belonging to his own or any other user's item.
(storyA:Card)-[:LINKS_TO]->(storyB:Card)
However, the owner of storyB may or may not want to link back to the first guy's story. I know you can ignore the direction of the relationship in a cypher query by doing:
(a)-[r]-(b)
But I read that explicitly creating bi-directional relationships is usually a bad idea. So if storyB wants to link back, how would you best represent this in the data model? Maybe another relationship type, like :LINKS_MUTUALLY or something, or a "mutual" boolean property on the :LINKS_TO relationship?

Regarding you first issue, it's usually better to have relationships rather than properties in this case.
I'd throw in FIRST and LAST relationships, like in this TimeTree, and model it as:
(a:Card)-[:DESCRIBES]->(i:Item)
(b:Card)-[:DESCRIBES]->(i:Item)
(c:Card)-[:DESCRIBES]->(i:Item)
(a:Card)<-[:FOLLOWS]-(b:Card)
(b:Card)<-[:FOLLOWS]-(c:Card)
(a:Card)<-[:FIRST_CARD]-(i:Item) //optional, for easy navigation
(c:Card)<-[:LAST_CARD]-(i:Item) //optional, for easy navigation
As for bidirectional relationships, the only are a bad idea if a relationship in one direction implies the other one. In your case, this is not the case, so creating (storyA:Card)-[:LINKS_TO]->(storyB:Card) and (storyA:Card)<-[:LINKS_TO]-(storyB:Card) is perfectly fine, since each relationship is there for a different reason.

Related

Node vs Relationship

So I've just worked through the tutorial and I'm unclear about a few things. The main one, however, is how do you decide when something is a relationship and when it should be a Node?
For example, in the Movies Database,there is a relationship showing who acted in which film. A property of that relationship is the Role. BUT, what if it's a series of films? The role may well be constant between films (say, Jack Ryan in The Hunt for Red October, Patriot Games etc.)
We may also want to have some kind of Character bio, which would obviously remain constant between movies. Worse, the actor may change from one movie to another (Alec Baldwin then Harrison Ford.) There are many others like this (James Bond, for example).
Even if the actor doesn't change (Main roles in Harry Potter) the character is constant. So, at what point would the Role become a node in its own right? When it does, can I have a 3-way relationship (Actor-Role-Movie)? Say I start of with it being a relationship and then, down the line, decide it should've been a node, is there a simple way to go through the database and convert it?
No there is no way to convert your datamodel. When you start your own Database first take time to find a fitting schema. There is no ideal way to create a schema and also there are many different models fitting to the same situation without being totally wrong.
My strategy is to put less information to the relationship itself. I only add properties that directly concern the relationship and store all the other data in the nodes. Also think of properties you could use for traversing the graph. For example you might need some flags or even different labels for relationships even they more or less are the same. The apoc.algo.aStar is only including relationshiptypes you want (you could exclude certain nodes by giving them a special relationshiptype). So keep that in mind that you take a look at procedures that you might use later.
Try to create the schema as simple as possible and find a way to stay consistent in terms of what things are nodes and what deserves a relationship. Dont mix it up.
Choose a design that makes sense for you! (device 1)-[cable]-(device 2) vs (device 1)-[has cable]-(cable)-[has cable]-(device 2) in this case I'd prefer the first because [has cable] wouldn't bring anymore information. Irrespective to what I wrote above I would have a lot of information in this [cable] relationship but it totally makes sense for me because I wouldnt want to search in a device node for cable information.
For your example giving the role a own node is also valid way. For example if you want to espacially query which actors had the same role in common I'll totally go for giving the role a extra node.
Summary:
Think of what you want to do with the data and choose the easiest model.

neo4j, how can search for relationship in this example?

I was learning neo4j, and following the tutorial provide atsearching for relationship.
I followed it, added two nodes and a relationship between them. I did exactly according to the tutorial in above link. But when i try to display the relationship i just added, by the following
MATCH (e)-[r:DO_SHOPPING_WITH ]->(cc)
RETURN r
it showed nothing.
to make sure, I displayed all nodes by
MATCH (a) return a
and it showed 2 nodes and the relationship between them.
Not only this case, I tried later examples, by similar search for relationship all are showed empty.
could anyone explain why I cannot display the relationship as it is told in the tutorial?
Pretty simple example, but somehow not working.
Please help!
It sounds like you're just talking about the graph result view. When the only items returned from a query are relationships, they won't show up, as it requires the nodes on either side of a relationship to be returned in order to display.
While this is current behavior, past behavior was able to display the start and end nodes of a relationship even if just relationships were returned, and it's not a bad idea to consider reverting to this previous behavior.
I think this issue on the browser project is related.

Compound relationship in neo4j

I'm playing around with neo4j - seeing what I can and can't do with it before suggesting it for something serious. One thing that I'm trying to work out is if you can have what I'm calling a compound relationship.
In my playing, I'm doing a family tree - it seems an ideal fit. I'm wanting to express that a life event occurred between two people - getting married for example - and where it happened. The MARRIED_TO relationship between two PERSON nodes is easy. I'm struggling with the relationship to the PLACE node though.
In my head, it seems that what I really want is a relationship that goes from the PLACE node to the MARRIED_TO relationship, and I don't think that's possible.
Alternatively, I could see the MARRIED_TO relationship going between three nodes, but that not only doesn't feel right but also isn't possible.
The best i can see to do is either have a EVENT node representing the marriage, which feels clunky, or else have relationships from both PERSON nodes to the PLACE, which is then duplication of data.
Is there a proper way of managing this kind of data? Or am I just missing something?
Consider "Marriage" being a vital part of your domain. Anything being an entity deserves a separate node - so "Marriage" (or Event) becomes a node. That node then can be connected to the two people and the location.

Neo4j/Cypher Query (user action) relationship direction

I am new to Cypher and trying to design a graphic database and store user behaviour. Thanks in advance!
Case Example:
1. A user visited a web page
2. A user owned a device (id:xxxxx)
In UML Class diagram, the arrow (relationship) is pointing toward to parent class
But, my point of view, not all relationship in Cypher are Parent-Child type, does it means that i should not apply this kind of concept into Cypher?
So, the question is "how to design the direction of relationship"?
(user)-[r:visited]->(webpage {url:xxx})
(user)-[r:owned]->(mobileDevice {uuid:xxx})
-- or --
(user)<-[r:visitedBy]-(webpage {url:xxx})
(user)<-[r:owned]-(mobileDevice {uuid:xxx})
Thank you again
This is a common question. The answer is that it's up to you! Relationship types can be whatever you choose and you should go with what is most comfortable. I would suggest that whatever you do, just try to be consistent.
Personally between "visted" and "visited by", I would go with "visited" because I think it makes more sense to be talking about the fact that the user visited a page, not that a page was visited by the user. I often recommend that people name their relationships so that the node-relationship-node makes a sentence. Since the user is the primary actor your sentence would be "(the) user visited (the) webpage". That might come from me being a native English speaker and the way that English sentences are formed, though.
As a side note, relationships in Neo4j are generally UPPER_SNAKE_CASE. Again, Neo4j doesn't restrict you from any one particular style, but that's what I've seen most. This guide gives a pretty good overview of common Cypher conventions:
http://nigelsmall.com/zen

multiple hierarchy in coredata

I do have a problem where I am having a hard time figuring out how to lay out the relationship in coredata. I tried to visualize the problem below.
Basically in my application users have STATEMENTS that are made of TERMS.
One or more TERMS make STATEMENTS[1].
Users can also tap on a term[2] and
create another statement that's connected to this term[3].
Once they solve this sub statement[4]
they can go back to the main statement [5] and highlight another term and so on.
They should be able to go deeper than one level if need be. Say, select another term in sub statement and create another statement etc.
I am not sure how to create such a schema in coredata.
I already have my TERM and STATEMENT entities, and I initially separated STATEMENT AND SUBSTATEMENT as two different entities but I am not entirely sure if this is a approach anymore.
I think a more efficient approach would be to store each statement in just one entity and have a relationship with TERM but I Am not sure how to figure out the levels.
I would appreciate any directions.

Resources