Can anyone explain why this apoc procedure returns null properties on the yielded value?? In this example the predicate is false.
MATCH (p:Posts)
CALL apoc.when(
p.region_audience IS NOT NULL AND NOT (2 IN p.region_audience),
"RETURN null",
"RETURN p AS post",
{p:p})
YIELD value
RETURN value,p.title;
So while value which should be equal to p is returned completely if you try to return value.title you get null. If your return p.title you do get the title. I know it has something to do with how the yield is computed.
Any help would be appreciated!
According to your condition p.region_audience IS NOT NULL AND NOT (2 IN p.region_audience), in apoc.when query:
In the ifQuery, the apoc.when returns RETURN null (value will be null) and in elseQuery returns p with Alias post.
So to access the result of the apoc.when query, you've to use the alias given in ifQuery or elseQuery : value.post.title.
Note that the result of value will always be null if the ifQuery is executed (when the condition is respected).
Related
Background
I have nodes which have been recording a specific attribute as LONG and I want them to be recorded as INT - I have amended my system's input code to now record them as INT, however I am looking to check Neo4J for anomalies.
The Data
I now have a mix of data, where some have been created as "int" some as STR and some are even null (which is ok in my data-structure)
CREATE (n:logs{value: "example", records: "30"})
, (n:logs{value: "example", records: 30})
, (n:logs{value: "example", records: null})
RETURN n
The Problem
I tried to verify if the system is now writing the "records" attribute as INT rather than string, so I tried the following query;
WITH datetime("2021-06-18T06:00:00").epochMillis AS threshold
MATCH(n:logs)
WHERE n.records <> tointeger(n.records)
COUNT(n)
This returns 1 - my NULL record, for some reason. But NOT the STR, as I would have expected.
I then try the following (18th June being the date of the update to my input system);
WITH datetime("2021-06-18T06:00:00").epochMillis AS threshold
MATCH(n:logs)
WHERE n.records = tointeger(n.records)
COUNT(n)
And this returns 0 - which again, I am not sure why.
So my question is, what am I doing wrong and how can I get to where I need to go. Which is ultimately to;
Check the system is saving as INT going forwards
Change all the pre-existing records from STR to INT.
I assume for #2 is will be something like
MATCH(n:logs)
WHERE n.records <> tointeger(n.records)
SET n.records = tointeger(n.records)
Additional Info
Community edition
Version X.x.x
No addins
Your query to update to integer is correct.
To clarify your assumptions, please run below queries in your neo4j desktop or browser and you will see what is going on.
1. RETURN toInteger("2021-06-18T06:00:00")
2. RETURN toInteger(null)
Both of them will return NULL. It means your claim below is NOT true
This returns 1 - my NULL record, for some reason. But NOT the
STR, as I would have expected.
You did return 1 but is it the string value of records ('30') rather than the NULL value.
Then when you run your query below
WHERE n.records = tointeger(n.records)
And this returns 0 - which again, I am not sure why.
It is because the integer value of a string date type is also NULL. Thus it will return no matching record.
If you want to count all nodes with non-integer attribute, including nulls then you can run below query.
MATCH(n:logs)
WHERE n.records <> tointeger(n.records) OR n.records is null
RETURN count(distinct n) as cnt
Result: 2
Remember, if n.records = "2021-06-18T06:00:00" then you need to convert it to an epoch value (the integer value of time in seconds or millis since 1/1/1970). If not, then tointeger(n.records) is null and will not match in your query.
Do something like below:
MATCH (n:logs)
WHERE tointeger(n.records) is null
SET n.records = datetime(n.records).epochMillis
RETURN n
Then do your original query (this is correct!), to clean up other non-integer values.
MATCH(n:logs)
WHERE n.records <> tointeger(n.records)
SET n.records = tointeger(n.records)
In cypher or APOC, Is there a way to execute multiple query based on multiple condition.
I need something similar this APOC
CALL apoc.do.case([condition, query, condition, query, …], elseQuery:'',
params:{}) yield value
But here as soon as we met 1st true condition it skip all further condition and query. I want to execute all those query where my condition is true.
In simple word , I am looking for something similar to java case statement (without break; between case)
Update
I ran following query to use multiple apoc.do.when but it seems only my second apoc.do.when is not executing:
CREATE (y:EVENT { _id: 1, localComponentID:'l1', externalComponentID:'e1'}) with y
call apoc.do.when(exists(y.localComponentID),"MATCH(e:EVENT) where
e.localComponentID = lcl and e._id <> y._id with y,e limit 1 create (y)-
[r:LOCAL_LINK]->(e)",'',{y:y,lcl:y.localComponentID}) YIELD value WITH value AS ignored, y
call apoc.do.when(exists(y.externalComponentID),"MATCH(e:EVENT) where
e.externalComponentID = ext and e._id <> y._id with y,e limit 1 create (y)-
[r:EXTERNAL_LINK]->(e)",'',{y:y, ext:y.externalComponentID}) YIELD value
WITH value AS ignored return ignored
If I run above query two time with _id = 1 in first run and _id=2 in second run, I expect two EVENT connected with LOCAL_LINK and EXTERNAL_LINK. But I am only getting LOCAL_LINK between them not the EXTERNAL_LINK. I am not sure what I am doing wrong.
Note : I am using limit 1 because In case of multiple match I just want to create LINK with one node.
Update 2
Got it working , In my sample query I was that not returning y from first apoc.do.when
Here is the updated query which works:
CREATE (y:EVENT { _id: 1, localComponentID:'l1', externalComponentID:'e1'}) with y
call apoc.do.when(exists(y.localComponentID),"MATCH(e:EVENT) where
e.localComponentID = lcl and e._id <> y._id with y,e limit 1
create (y)-[r:LOCAL_LINK]->(e) RETURN y",'',
{y:y,lcl:y.localComponentID}) YIELD value WITH value AS ignored, y
call apoc.do.when(exists(y.externalComponentID),"MATCH(e:EVENT) where
e.externalComponentID = ext and e._id <> y._id with y,e limit 1
create (y)-[r:EXTERNAL_LINK]->(e)",'',{y:y, ext:y.externalComponentID})
YIELD value
WITH value AS ignored return ignored
You can just call the APOC function apoc.do.when for each condition/query pair (with an empty string as the else argument).
For example:
CALL apoc.do.when(<condition1>, <query1>, '', {}) YIELD value
WITH value AS ignored
CALL apoc.do.when(<condition2>, <query2>, '', {}) YIELD value
WITH value AS ignored
.
.
.
Since your comments indicate your queries are all write-only, the above example assigns the return values to an ignored variable (that you can ignore).
I am trying to figure out, how to deal with null values of an OPTIONAL MATCH result. I would like to return an empty array instead of null.
Returns the users as list, regardless of the number of users:
MATCH(u:User {some_property: "some_value"})
RETURN properties(u) LIMIT 25
Returns the users as list, if the number of users > 1, otherwise null:
MATCH(u:User {some_property: "some_value"}), (x:SomeLabel {id: "<<someID>>"})
OPTIONAL MATCH (u)-[:SOME_RELATION]-(x)
RETURN properties(u) LIMIT 25
Returns the users as a nested list (array in an array), if the number of users > 1, otherwise as list.
MATCH(u:User {some_property: "some_value"}), (x:SomeLabel {id: "<<someID>>"})
OPTIONAL MATCH (u)-[:SOME_RELATION]-(x)
RETURN COLLECT(properties(u)) LIMIT 25
What is an elegant way to always return a list, neither nested nor null? Using conditional expressions only?
I'm not sure where you're getting that syntax from, RETURN as ... isn't valid, and even if it were, properties() returns a map, not a list. Also in your last query, COLLECT(properties(u)) should return an empty list even if u is null, so you shouldn't need to force the return of an empty list.
But for some other query where you want to return an empty collection instead of a null, you can use COALESCE() to return a default value you provide if the first expression is null.
...
RETURN coalesce(possibleNullVariable, []) as result
I have a problem with List of objects, which one have field for example Metadata, which is null. So when i use a.Metadata.ToLower().Contains(someText)
It shows me error, about null value. How Can I fix it ?
P.S. I see this problem first time, I tried to do the same with other List of objects which one also have null fields and it works, where can be problem ?
instead of
.Where(a => a.Metadata.ToLower().Contains(someText))
do
.Where(a => a.Metadata != null && a.Metadata.ToLower().Contains(someText))
Linq don't like null value but sometime we can't like exemple above just ignore what is null so i took habitude to cast null into the empty or minimal value.
so the value even null are cared like all other value .
have you tried a null fusion opérator in your linq query?
its : ?? operator
it will return rigth part if your data is null (in my case i return a string empty).
exemple i want sort a machine list that have some null string.
ListControleMachine.Sort((a1, a2) => (a1.MachineName ?? string.Empty).CompareTo(a2.MachineName ?? string.Empty));
you see when i sort my machine if its name is null i transform null into String.empty
name <> myname
I feel a bit stupid asking this question, but I am using the predicate above in a subquery. I was expecting to see all rows where name was not equal to my name. However, rows that have a NULL value for name are not being returned. Is this correct behavior?
Yes, that is to be expected. See Null Values in the "Predicate Programming Guide":
A comparison predicate does not match any value with null except null
(nil) or the NSNull null value (that is, ($value == nil) returns YES
if $value is nil).
...
If you want to match null values, you must include a specific test in addition to other comparisons, ...
That means that both "name = myname" and "name <> myname" evaluate to NO if name
is NULL.
You can change your predicate to
name <> myname OR name = NULL
to cover both cases.