Iteration between values of a property

Hello!

I have a sequence of code (including CALL apoc.nodes.link procedure) that uses a property value 'X' to run.

I need to iterate the same sequence with a list of the property values, namely: 'Y','Z',...

Of course I can copy/paste/replace 'X' by 'Y' and so on but is there a more elegant way to run this iteration in a For -- Do -- End Loop?

Thanks for your attention - Your feedback welcome.

Thanks for the feedback, but unfortunately the example in the Manual (yes, I can find the Manual topic by myself) is obscure (too complex) and that is the reason I am asking the community.

I need help using FOREACH with a simple list of values ( text names in my case) where I will be a able to run for each value a sequence of cypher instructions.

Thanks for the attention.

Can you give some example data of what you are trying to do? I can't quite figure out what you want from your brief description.

The documentation of FOREACH is a bit skimpy, I will admit.

The solution to my request is through
WITH (‘name1’,’name2’’,’name3’,...)
UNWIND

All these features FOREACH, LISTS, WITH UNWIND are murky for someone who simply wants to run FOR ... THEN... ELSE ...END loop.

The examples in the manual are mostly with RETURN clause but MATCH, MERGE are not in the same category so when you try them you either have a syntax error or the sequence does not work.

I suggest that the Cypher Manual should include basic examples with Create,Merge clauses.

Hope this is helpful.

Thanks for the attention.

This is my intermediate level of understanding Cypher, which may be flawed...

The murkiness is that Cypher (and other SQL languages) are declarative (mostly). The FOREACH on the other hand has more of a procedural flavor... COLLECT combines things into a LIST which is then more an entity that has a procedural flavor. The UNWIND coverts a list of elements back into declarative entities, which rest of Cypher can works.

I suspect the WITH statements are syntactic sugar that keeps the declarative statements localized yet lets you pass results between the declarative statements.

Consider this Cypher:

(actor:Person)-[:ACTED_IN]->(m:Movie)<-[:ACTED_IN]-(coactor:Person)

There isn't a procedure of "first step", "second step", etc. This is a declarative statement. (Under the hood, the Cypher code does get converted into a set of procedural instructions, which is how computers work... So the declarative nature is a bit of an illusion.)

I think in theory, queries then can be run in parallel without changing anything. (e.g. match actors in parallel and get coactors in parallel.)

Or something like that. I'm still figuring it out.

SQL and Cypher takes a bit of getting used to. It is a peculiar thing.

I hope this helps a little...

... it helps a lot!

Many thanks for pointing to the declarative vs procedural question: I need to think more about the issues you raised it will help me navigate in this labyrinth.

My programming background is procedural and I am a beginner and self-taught in Cypher and let's take a more practical and ground level perspective.

My need s trivial: I have a list of values (i.e. names) that I want to set as property-value in a basic sequence of declarative statements. As I already mentioned I can copy/paste/replace but this is disgraceful for a programming language.

When I discover all these primitives you mentioned I wonder what they really mean (the Manuals don't help) and question if in all this abundance there is no redundancy?

Now consider the following:

  1. the real-time syntax analyzer provides no guidance while you are still coding your statements,
  2. When your query is incorrect you get a message that many times is not helpful to understand where the error is,
  3. the worst of all: there is no UNDO to alleviate your pain when one of your declarative statements go wild.

In conclusion: If some of the features raised above where implemented (namely Manual with basic examples, more guidance in syntactical analysis and please please UNDO) it would spare scores of hours lost in trying to achieve such an elementary task.

There is room for substantial improvement, that is the good news!

Many thanks for your attention...

Hello Guys

I think there is a lot of room for help here.
It's 1h00 AM in Canada (BC) so I have to go to the bed.

I can explain in details tomorrow but for now I would suggest:

1 - The non technical part of the neo4j Cypher manual, the introduction, they explain their philosophy and a huge but shortly presented part of the cypher language mechanics.

2 - The day I understood everything about Cypher is when I understood this:

These is two worlds:

The graph world

AND

The projected data world

Each of them have their own clauses and functions, so yeah if you look at all theses clauses as a part of a unique system or philosophy you get lost. But once you get it, it's magic.

Just to be sure about what you are trying to do here Alexandre, you want to create one node with something like a name property for each name you got on a simple names list?

If yes

UNWIND ["A","B","C"] AS name
CREATE (:Node {name: name})

The UNWIND clause create a row per element in your list and the instruction CREATE is repeated for each row created.

1 Like

Hello Gabriel!

Thanks for your valuable feedback particularly on how to better understand Neo4j conceptual framework split. as you suggest, in two sub-worlds. I am going to read the introduction and look forward to your additional inputs if applicable.

Indeed, the UNWIND clause is the right way to solve my ultra basic need.

OK, I must be shamefully low-low smart but it took me hours to come to this solution, this is outrageous.

I come from the procedural world where you can set breakpoints, view variables and so on... In this declarative world you give a shot with the following possible outcomes: (1) Sorry, there is a syntax error (not always properly indicated, go figure), (2) Nothing happens: go figure why, (3) something happens but your statements generated a wild bunch of nodes, relations : can I UNDO? No, you must repair your damages with a new set of clauses, which if erroneous increase further the damage, and finally (4) the sweet spot your query creates gracefully all your requests, you feel like a "happy few".

Thanks for your attention, wish you all a great festive Sunday.

Cheers,
Alexandre

A few things I do:

  1. Modify my potentially dangerous query so that instead of modifying any nodes, return the values that I think I want.

E.g. something like

MATCH (n) ... // some complex query.
// SET n.property = value // some complex value
RETURN n.name, value // see in a table whether the values to be changed look OK 

And if it makes sense, then uncomment the SET (or whatever modification statements you have)

  1. I do a DB clone. (click on the three dots, and the clone.). After you do that, change the name of the DB to something like 'Name 2020-01-11". Also, you can write some notes in the area below the DB info, to keep track of what's going on. (It's not obvious you can do that... click in the area above the Open and Stop buttons).

  2. Many APOC functions can be used to fix problems.

You can also use the internal id of a node id(node) to help distinguish between things that seem the same but aren't. Be ware that Neo4J recycles its internal node ids, so they can only be relied upon within a statement (or something like it... I believe it's OK if there are some deletes and creates....)

I hope that helps.

I hope this draw might help a little bit to understand what I was talking about when I wrote "two worlds". I don't have so much time to improve it for now.

Here you can see two distinct queries and their effect on the graph world and the projected data world. By the way, as you will probably figure out soon, the projected data world is always tempory. It's to exchange some data between two different part of the query ( usually to split the read and write part of a query ) with the clause WITH or to export the result with the clause RETURN who trigger the end of the query.

1 Like

Hello Gabriel!

I can’t find the non technical text you mentioned, the introduction on the Manual is very limited on the topic of the two sub-worlds.

Thanks for the attention, looking forward for your feedback.

very excellent representation.

other database example -
RDBMS -> a lot of difference between select * from and select co1,co2,col3. the former is NOT performant, and the latter is Performance Efficient.
MongoDB -> Projections

The specific columns are chosen so that it fits less in memory and when joins happen they can get the predicate mode effective.

The neo4j cypher manuel doesn't explicitly talk about the Graph and the projected data itself as two splitted domains or worlds. But they should in their introduction as it's the main point to understand how different clauses will not behaves as you can expected at all.

Once you get it, combining both of them gives you a so much short and powerfull language.

But here is the quick list:

GRAPH:

MATCH
OPTIONNAL MATCH
CREATE
DELETE
DETACH DELETE
SET
REMOVE
MERGE
FOREACH <- Can use projected data as an entry but always works on the graph

PROJECTED DATA:

RETURN
WITH
UNWIND
ORDER BY
SKIP
LIMIT
UNION
UNION ALL

These clauses can encode ( nodes and relations belonging to the graph ) as a json string but still everything in these clauses will be a sequence of rows and columns at the end.

BOTH:

WHERE
WHERE EXISTS

Here is the link to the offical neo4j 4.2 Cypher manuel

1 Like

It's seems that the rule "get only what you need", and no I don't work for the U.S liberty insurance, works for other DBMS too.

1 Like