APOC if.Then.Then.Else with splits

I want to use APOC because I need to set the node’s label using values from my dataset, a csv file

Lets say I have a column element like this

LabelTerm1; attribute1Name-Value1;attribute2Name- Value2;…..

I would like to spilt this into three things. The first is the Label for the node and the next things (two or more) the nodes Attributes. I am using APOC because I can dynamically set the nodes label (s) where I can't do this in standard Cypher.

What is a good way to do this.. I need to say something like

Split this element into a list, take the first one and make that the node’s label and then the following ones split them again on a “-” and create as many node attributes as I need.

See what I am asking?

Any good ideas?

Thanks for helping me out! thanks guys!

try this:

with "LabelTerm1;attribute1Name-Value1;attribute2Name-Value2;attribute3Name-Value3" as input
with split(input,";") as elements
with head(elements) as label, apoc.map.fromPairs([i in tail(elements)|split(i,"-")]) as map
call apoc.create.node([label], map) yield node
return node
{
  "identity": 1,
  "labels": [
    "LabelTerm1"
  ],
  "properties": {
    "attribute3Name": "Value3",
    "attribute2Name": "Value2",
    "attribute1Name": "Value1"
  },
  "elementId": "4:189f1e54-9faa-4302-a82e-cf9e0e371d57:1"
}

Note: make sure there are no spaces before or after each delimiter.

I will try this.. but.. it looks like this is exactly what I need.. Dude.. you are the best.. man.. if this works.. you would have saved my AGAIN.. Dude.. Thanks man.. you are wonderful.. I only wish I could do something for you. let me work on this and I will let you know what happens.. thanks man

now I just have to figure out how to Skip elements in the csv file that are blank.. .. :)
will dig into the APOC stuff to see if I can find that out.. You cant mix Cypher
ForEach(_ In Case When (row.Country is not null) Then [1] Else End|
sort of things with Apoc commands.. so.. must be something nice in APOC to do this.. :slight_smile:

Can you give me an example of what you have and want to do?

No need to do anything for me. Your joy and appreciation is enough

You can leverage cypher's trim() function if you can't guarantee no spaces before or after each delimiter.

I will draw up an example.. thanks man.. I am use to doing something like
ForEach(_ In Case When (row.Country is not null) Then [1] Else End|
do my cypher here..
)

That way i know my Country column for that row is, not null.. So.. in apoc there must be a way to test this.. so I dont do a split on a null and throw an exception.. if you see what I am asking.. well it is 11 at night.. I will put together an example.. see the problem and reason for the question? I found some APOC if then else mechanism that I will explore.. Thanks man for helping me.

I prefer using a call subquery instead of the for each. The similar solution would be:

Call {
with row
With row.Country is not null
//do some cypher
}

The one caveat is that you can’t return anything, as the rest of the query will terminate for the rows that don’t meet the criteria.

apoc does have procedures for executing condition logic. For read-only cypher, there is apoc.case and apoc.when. The equivalent procedures where you can have write operations are apoc.do.case and apoc.do.when

Let me know what example you come with and we can try to solve it.

Wow
Cool!
Thanks man!

So slam in this map stuff inside a call
Neat.
Wow that’s easy
See with the for each thing
You can’t do APOC in there
Sigh

The forEach is limited to update statements an another forEach. As such, it has limited use. The call subquery can execute any cypher.

Well hopefully your APOC stuff can go in there :blush:

Not real sure how to fix this and.. I am already on to many projects at the labs.. way over allocated but..

Can you take a quick look at this..

load csv with headers from file:///example.csv as exampleRow with exampleRow

Call {

With exampleRow.LevelOne is not null

with split(exampleRow.LevelOne,";") as elements

with head(elements) as label, apoc.map.fromPairs([i in tail(elements)|split(i,"-")]) as map

call apoc.create.node([label], map) yield node

return node

}

The first “with” in a call subquery has to be a simple import, meaning just listing the variable to import. A second “with” can be used to filter using a “where” clause.

This should fix it.

load csv with headers from file:///example.csv as exampleRow with exampleRow

Call {
With exampleRow

With exampleRow
Where exampleRow.LevelOne is not null

with split(exampleRow.LevelOne,";") as elements

with head(elements) as label, apoc.map.fromPairs([i in tail(elements)|split(i,"-")]) as map

call apoc.create.node([label], map) yield node

return node

}

When you return something in a subquery it gets appended to the result in the outer query. In your case, when the where clause condition is not met, the subquery will return null and the outer query will terminate. In your case you have nothing following the subquery, so this is not an issue.

Also, you don’t need the subquery for your use case. The following should work as well.

load csv with headers from file:///example.csv as exampleRow 

With exampleRow
Where exampleRow.LevelOne is not null

with split(exampleRow.LevelOne,";") as elements

with head(elements) as label, apoc.map.fromPairs([i in tail(elements)|split(i,"-")]) as map

call apoc.create.node([label], map) yield node

return node

Wow
This is a whole new way of doing things!
Thanks man
Thanks
I will build all this out in the morning !!

1 Like

One small question.. sorry to bother you again.. First.. this works great! But lets say, instead of creating attributes in the newly created node.. the items after the node label were other nodes (proxy nodes) that i wanted to connect to the first node..
something like this maybe..
ParentNodeLabel(ParntAttrName1-ParntAttrValue1|ParntAttrName2-ParntAttrValue2);ChildNode1Label(AttrName1.1-AttrValue1.1|AttrName1.2-AttrValue1.2);ChildNode2Label(AttrName2.1-AttrValue2.1|AttrName2.2-AttrValue2.2|AttrName3.2-AttrValue3.2)
so ParentNodeLabel would point to ChildNodes 1 and 2, each would have attributes enclosed in something like parentheses.. see sometimes I need the parent node to hold values, and sometimes I need to have that parent node points to proxy nodes that will later be filled in from other data sources, thus their ids, shown here in attribute values. These formats will not be mixed in the same file.. that would be nuts. Nice but.. nuts. Hope this makes some kind of sense.. :slightly_smiling_face:
thanks man.. thanks again.. sigh.. complex projects here.. :slight_smile:

So, you want to do something similar, but now provide a parent and multiple child nodes in your encoded string? If this is correct, I think I can work it out. Can we change the encoding so it is easier? If you are flexible on it, the following would be easier than enclosing the attribute/value pairs in parenthesis.

"ParentNodeLabel:ParntAttrName1-ParntAttrValue1|ParntAttrName2-ParntAttrValue2;ChildNode1Label:AttrName1.1-AttrValue1.1|AttrName1.2-AttrValue1.2;ChildNode2Label:AttrName2.1-AttrValue2.1|AttrName2.2-AttrValue2.2|AttrName3.2-AttrValue3.2"

This would work too:

"ParentNodeLabel|ParntAttrName1-ParntAttrValue1|ParntAttrName2-ParntAttrValue2;ChildNode1Label|AttrName1.1-AttrValue1.1|AttrName1.2-AttrValue1.2;ChildNode2Label|AttrName2.1-AttrValue2.1|AttrName2.2-AttrValue2.2|AttrName3.2-AttrValue3.2"

Sure
No problem !!
Just need a good way to define proxy nodes with attributes
Change the syntax
No problem

Here you go:

with "ParentNodeLabel|ParntAttrName1-ParntAttrValue1|ParntAttrName2-ParntAttrValue2;ChildNode1Label|AttrName1.1-AttrValue1.1|AttrName1.2-AttrValue1.2;ChildNode2Label|AttrName2.1-AttrValue2.1|AttrName2.2-AttrValue2.2|AttrName3.2-AttrValue3.2" as row
with split(row,";") as items
with head(items) as parent, tail(items) as children
with split(parent,"|") as parentItems, [i in children | split(i,"|")] as childItems
with 
    head(parentItems) as parentLabel, 
    apoc.map.fromPairs([i in tail(parentItems)|split(i,"-")]) as parentMap, 
    childItems
call apoc.create.node([parentLabel], parentMap) yield node
with node as parentNode, childItems
unwind childItems as child
with 
    parentNode, 
    head(child) as childLabel, 
    apoc.map.fromPairs([i in tail(child)|split(i,"-")]) as childMap
call apoc.create.node([childLabel], childMap) yield node
create(parentNode)-[r:HAS_CHILD]->(node)
return parentNode, r, node as childNode