Foreach CASE or not?

Dear community,

I'm struggling to grasp the essence of cypher.

my set :
USER (FIRSTNAME, LASTNAME, ...., LISTOFNAMES)

user1{'firstname1', 'lastname2', ....., 'firstname2 lastname2, firstname11 lastname11, firstname100 lastname 100'}
user2{'firstname2', lastname2', .... , 'firstname44 lastname 44'}
...

coming from a form. Users can name other users with their full name ('Firstname Lastname', not Firstname, Lastname).

I want to examinate the LISTOFNAMES. If inside this list an other user from my set is found (by comparing the concatenate of userX Firstname and Lastname), THEN I want to create a relationship between the two (I managed to do that somehow)
If the user is not found, I want to create this new user

LOAD CSV WITH HEADERS from 'file:///doc.csv' as row
match (n)
with n, split(row.LISTOFNAMES, ", ") as fullnames
unwind fullnames as fullname
match (m)
where fullname = m.Firstname + ' ' + m.Lastname
CREATE (n)-[rel]->(m)
(so far, that only does half of the job, and I cannot figure how to make the other case)

I tried the CASE and Foreach but either I get stuck in the process, or I get stuck by the syntax. It's very tricky.

Would you be so kind to guide me towards examples I could relate to ?

Your 'match(n)' is way out of place. The flow of the query as is written should be the following:

  1. A row is returned from the csv file
  2. The match(n) returns a row for every node in your database, while appending the 'row' value to each row. Thus, 'row' is being repeated for every node 'n'.
  3. For every node 'n', you expand the single row into a new set of rows, one for each full name of node 'n'. This row also includes the 'row' map from the csv file.
  4. You find all nodes in your entire database that match the full name (this string concatenation is repeated over and over).
  5. You create a relationship between this node 'n' and every matching node 'm'.
  6. Steps 4 and 5 are repeated for every node 'n' and name

The above is also repeated for every 'row' in the csv file.

Good thing is we are here to help, and this most likely can be simplified to something that is easily understood.

Can you provide a sample of the doc.csv file? You also need to define a data model. You should not use generic nodes without labels. You should define labels for each type of entity in your data model. Since you have names, you may want to define a 'Person' label for these nodes. Also, what type of relationship do you want between these person nodes?

A great tool to diagram a data model is arrows.

Great,

I'll have a look at tour comprehensive answer and work on it.
You just said what i suspected.

Hello there,

here is a doc.csv : there
here is arrow representation I guess :

Let me correct the code above because I wrote a version for you that is not what I'm using, and I messed up a bit.

LOAD CSV WITH HEADERS from 'file:///doc.csv' as row
FIELDTERMINATOR ';'
MERGE (n:juggler{LastName:row.LastName, })
with n,split(row.relatedto, ", ") as fullnames
UNWIND fullnames as fullname
MATCH (m:juggler WHERE m.Firstname + ' ' + m.Lastname = fullname)
MERGE (n:Juggler)-[:relatedto]->(m:Juggler)

So far this is working.

so how can I do the other part ?

(note : I'm still trying to figure out constraints and indexes)

  • the way I see the process (ideally)
    1 - a row is returned from the csv file
    2 - a new user is created if not existing already
    3 - I removed the n in the split, and now split the relatedto field
    4 - for every name in that field, I'm matching with existing user fullname
    5 - create a relationship between the two
    6 - (still to do) if no match, create a new user.

I cannot emphasize how much I appreciate your help.

This is much better.

When you Match or Merge, you should do so using a unique identifier or identifiers (if the data warrants a composite identifier). You do not want to match or merge with all the node's properties. In your case, what uniquely identifies a Juggler node is either their full name or first name and last name combination. You could implement your solution with either identifier(s). For illustrative purposes, let’s pick first name and last name.

You state you want to create the related juggler if the juggler does not exists. You can achieve this by using merge instead of match.

LOAD CSV WITH HEADERS from 'file:///doc.csv' as row
FIELDTERMINATOR ';'
MERGE (n:Juggler {LastName:row.LastName, FirstName:row.FirstName})
with n, split(row.relatedto, ", ") as fullnames
UNWIND fullnames as fullname
with n, split(fullname, ' ') as parts
MERGE (m:Juggler {LastName:parts[1], FirstName:parts[0]})
MERGE (n)-[:RELATED_TO]->(m)

this is working great thanks.

Now, let's say I have a second list of relatedpeople, here named dislikes.

with n, split(row.relatedto, ", ") as fullnames, split(row.dislike, ",") as dislikes
UNWIND fullnames as fullname
with n, split(fullname, ' ') as parts
MERGE (m:Juggler {LastName:parts[1], FirstName:parts[0]})
MERGE (n)-[:RELATED_TO]->(m)

UNWIND dislikes as dislike
with n, split(dislike, '  ') as parts2
MERGE (m:Juggler {LastName:parts2[1], FirstName:parts2[0]})
MERGE (n)-[:RELATED_TO]->(m)

doesn't work

I tried :

with n, row 
UNWIND split(row.relatedto, ",")  as fullname
with n, split(fullname, ' ') as parts
MERGE (m:Juggler {LastName:parts[1], FirstName:parts[0]})
MERGE (n)-[:RELATED_TO]->(m)

UNWIND split(row.dislike, ",") as dislike
with n, split(dislike, '  ') as parts2
MERGE (m:Juggler {LastName:parts2[1], FirstName:parts2[0]})
MERGE (n)-[:RELATED_TO]->(m)

without more success
how can I keep the row data ? So far what worked is performing the two operations separately.

'dislikes' is out of scope when you are referencing it. You need to include it in the second 'with'

with n, split(fullname, ' ') as parts, dislikes

Note: I think you have two spaces in the split for dislike.

hello,

it is working, thanks !

1 Like