Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
06-14-2021 07:28 AM
I am struggling a bit to get the last page node from the last event.
Blue node: Session, Grey node: Events, Pink node: Page
This would be the domain: I am trying to track all the user events in a web and each event belongs to one page. If an event does not have a page it means, it belongs to the last event that has a page. So if we get the last page and it is the same page url, we do not create the page but in other case yes.
So for example if a run this query I get all the pages but I want to return or collect the last one
MATCH (u:Admin {uuid: "xxxx"})-[:LAST]->(s:Session)-[:LAST]->(e:Event)
WITH e
MATCH (e)<-[:NEXT*]-(pageEvent:Event)-[:FETCH]->(p:Page)
RETURN e, pageEvent, p
06-15-2021 11:03 AM
@undefined21
I dont completely understand the model but to find a node which is the last in a series then the node would have no outgoing relationships.
match (n) where size ( (n)-[r]->() ) = 0 return n;
will return all n
nodes which have no outgoing relationships. Perhaps you can use this example in your query. And if you need to change match (n)
to match (n:Event)
so as to provide more clarity
06-16-2021 04:20 AM
You might be right, I might not explain clearly. The blue node would be a user session, we keep there the main information related with that session. Let's say, when we access to the domain, we create a session node.
After, the domain has different pages, the pink nodes, /users/list, /user/create, /users/groups. Then, in each page, we can interact which it would be mainly the API request.
For example if you access to the /users/list page, first event would be FETCH_USERS. Next event could be choose the desired user, we create CHOOSE_USER event. Finally, we will change the username and the belonging event would be CHANGE_USERNAME.
When we change the username, we will go to /users/groups page and the event would be FETCH_GROUPS, and so on. Like this we will create kind of timeline of the user how it interacts on the session.
From the above picture, our example would be the orange square:
The reason that I am not having in each event a page because I thought it would be repetitive and not necessary. Also when I would like to get some statistics about the frequency of visited pages, it wouldn't count correctly. For example in our example /user/list is visited once but if we will add in each event a page would be three page visits and that one would be wrong.
Explained better the domain, now I would like to create an event, imagine it will be DELETE_GROUP. To connect a page to the event or not, we have to get the last visited page. In that case, we would anchor the sessionId (green square) and we will go traverse from the LAST edge until we will find the events with FETCH edge which it will connect the page node. If the actual event page is the same as the last page, we are not creating a page (our example case) if not, connect the last event with a page.
So I created few queries to achieve that:
MATCH (s:Session {uuid: "xxxx"})-[:LAST]->(e:Event)
WITH e, s
// Get the Events that has Page
MATCH path = ((e)<-[:NEXT*]-(pageEvent:Event)-[:FETCH]->(page:Page))
WITH length(path) as hops, page, s
WITH collect(hops) as hopList, page, s
ORDER BY hopList ASC
// Get the last page of the session
LIMIT 1
CREATE (newEvent:Event { type: 'DELETE_GROUP'})
WITH page.url as pageUrl, '/user/groups' as actualPage, newEvent, s, page
// Create a new Event and maybe a page also
CALL apoc.do.when(pageUrl = actualPage, 'CREATE (session)-[:LAST]->(new)', 'CREATE (session)-[:LAST]->(new)-[:FETCHA]->(page)', {session: s, new: newEvent, page: page}) YIELD value
RETURN *
In the second example, I refactored a bit. One question, when we create a list with collect, does it always order in desc mode?
MATCH (s:Session {uuid: "xxxx"})-[:LAST]->(e:Event)
WITH e, s
// Get the Events that has Page
MATCH path = ((e)<-[:NEXT*]-(pageEvent:Event)-[:FETCH]->(page:Page))
WITH collect(length(path))[0] as hops, s, page
LIMIT 1
CREATE (s)-[:LAST]->(newEvent:Event { type: 'DELETE_GROUP'})
WITH page.url as pageUrl, '/user/groups' as actualPage, newEvent, page
// This CALL writes in DB
CALL apoc.do.case([pageUrl <> actualPage, 'CREATE (new)-[:FETCHA]->(page)'], '', {new: newEvent, page: page}) YIELD value
RETURN *
As a new user with neo4j which would be the best approach or is there another way to do?
Thanks for your time!
All the sessions of the conference are now available online