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)
Related
I have list property [1,2,2,0]. The value is the list default to type of long. To convert to a list of type integer I am using
apoc.convert.toIntList([1,2,2,0])
but the result is still a list of type long.....however
apoc.convert.toStringList([1,2,2,0])
does result in a list of strings. This my query:
MERGE (bs:Bslot {date: $date})
ON CREATE
SET bs.slots = [1,2,2,0]
RETURN {slots: apoc.convert.toIntList(bs.slots)}
What am I doing wrong here?
It is working as expected; see below example:
WITH [1,2,2,0.99] as slots
RETURN {slots: apoc.convert.toIntList(slots)}
Result:
╒════════════════════════════════════════╕
│"{slots: apoc.convert.toIntList(slots)}"│
╞════════════════════════════════════════╡
│{"slots":[1,2,2,0]} │
└────────────────────────────────────────┘
Notice that 0.99 (float) becomes an integer.
In your example; MERGE will not update slots property when that node Bslot with date equals $date. It is because it will only set the value of slots to [1,2,2,0] if that node is new (create).
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).
I have this query for filtering a sheet by multiple criteria:
=query(A2:H,"select A,B,C,D,E,F,G "&IF(K3="where","","where A >= date '"&TEXT(K3,"yyyy-mm-dd")&"'")&"
"&IF(K4="","","and A <= date '"&TEXT(K4,"yyyy-mm-dd")&"'")&"
"&IF(K5="","","and B matches '"&UPPER(K5)&"'")&"
"&IF(K6="","","and C matches '"&UPPER(K6)&"'")&"
",1)
It works fine but, when all the arguments return false, I get the whole range, presumably as the query becomes just select A,B,C,D,E,F,G.
Is there any way I can force it to return nothing, or an error even. I Tried just putting a random OR C matches 'nothing' at the end but it still returned everything.
Chris, you could put an IF statement around the whole QUERY. Something like:
=IF(AND(K3="where",K4="",K5="",K6=""),"",QUERY(....))
Would that work for you?
Ok, I'm trying to figure out if there is a query that can give me something similar to the following:
MATCH (practiceTest:PracticeTest)
RETURN count(distinct practiceTest.passed===true), count(distinct practiceTest.passed===false)
I'm aware that this query does not work, but I'm curious if there is a way to do something similar to this, without having to write the following:
MATCH (practiceTest:PracticeTest)
WHERE practiceTest.passed = true
RETURN count(distinct practiceTest);
MATCH (practiceTest:PracticeTest)
WHERE practiceTest.passed = false
RETURN count(distinct practiceTest);
Thank you!
another approach
MATCH (p:PracticeTest)
WITH COLLECT(p.passed) AS results
RETURN SIZE([result IN results WHERE result=true]) AS num_passed,
SIZE([result IN results WHERE result=false]) AS num_failed
You could count the result of a CASE statement when a practiceTest is true and then count again when the reulst is false.
MATCH (p:PracticeTest)
RETURN count(CASE WHEN p.passed = true THEN 1 END) AS num_true, count(CASE WHEN p.passed = false THEN 1 END) AS num_false
The following query is pretty efficient in time and space. It only makes one aggregating function invocation, creates only one list, and only makes one pass through that list:
MATCH (p:PracticeTest)
WITH COLLECT(p.passed) AS data
WITH data, REDUCE(ps = 0, x IN data | CASE WHEN x THEN ps+1 ELSE ps END) AS passes
RETURN passes, SIZE(data)-passes AS fails
NOTE: This query does not count p nodes that have no passed property. Also, the passed value must be a boolean.
Returning counts of boolean values
If all you want to do is return the count of how many passed or failed, you could use the following:
MATCH (practiceTest:PracticeTest)
RETURN practiceTest.passed AS PassedTest,
count(practiceTest) AS Frequency
which will return something like
╒════════════╤═══════════╕
│"PassedTest"│"Frequency"│
╞════════════╪═══════════╡
│true │17682 │
├────────────┼───────────┤
│false │27152 │
└────────────┴───────────┘
Converting boolean to 1/0
If you wanted to convert True/False into 1/0 as some of the replies suggested, you can convert the boolean to an integer.
In Neo4j v4.3+, the toInteger() function converts a boolean to 1/0. If you're on an earlier version, you can use apoc.convert.toInteger(), but be aware that function is deprecated and will be removed in 5.0.
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).