1

I've recently started working on Cypher. Created a Book database. I want to implement following things using Cypher query-

  1. Find all books containing at least 1 capital letter in its isbn property value.
  2. Traverse over all of such books and for each book if one more book(node) is present with same value but in small case(If other node is present then it'll always have small case isbn value) then add label to capital value node with name Deleted.
  3. If only one node present with capital value then convert its value into small case.

Following is the query I wrote, but getting error about unexpected case-

 CALL apoc.periodic.iterate(
'MATCH (res:Book) WHERE res.isbn =~ \'.*[A-Z]+.*\' RETURN res', 
'MATCH (res2:Book) WHERE toLower(res.isbn) = toLower(res.isbn) 
RETURN count(res2) as rescount WITH CASE rescount 
WHEN 1 THEN set res.isbn=toLower(res.isbn) 
WHEN 2 THEN set (res:Deleted) END',{})

Error-

{"Invalid input 'r': expected whitespace, comment, '{', node labels, MapLiteral, a parameter, a parameter (old syntax), a relationship pattern, '(', '.', node labels or rel types, '[', '^', '*', '/', '%', '+', '-', "=~", IN, STARTS, ENDS, CONTAINS, IS, '=', "<>", "!=", '<', '>', "<=", ">=", AND, XOR, OR, WHEN, ELSE or END (line 3, column 21 (offset: 187))\n"    WHEN 1 THEN set res.isbn=toLower(res.isbn)"\n                     ^": 1                                                                                                                            }
nik
  • 1,464
  • 4
  • 18
  • 32

2 Answers2

1

Unfortunately, you cannot combine set n.<prop> and set:<label> into one case-when statement.

1 CALL apoc.periodic.iterate(
2    "MATCH  (res:Book) where res.isbn =~ '(?)[A-Z].*' RETURN res",  
3    "MATCH (res2:Book) WHERE toLower(res2.isbn) = toLower(res.isbn) 
4     WITH res, count(res2) as rescount
5     SET res.isbn = CASE WHEN rescount = 1 THEN toLower(res.isbn) END 
6     WITH res WHERE rescount = 2
7     SET res:DELETED", {})

line 1 is iterate statement
line 2 is passing all books that starts with upper CASE letter (e.g. Aaa)
line 3 is find other books with same isbn with line 2 but lower case (I fixed your typo on the sample query). For ex:  Aaa and aaa
line 4 count those books with same isbn in line 2 
line 5 set the isbn to lower case found in line 2 when no other duplicate book is found (rescount = 1)
line 6 get only those books in line 2 that has duplicated isbn (res2) in line 3
line 7 update the label of this book filtered in line 6 to DELETED

sample result:

enter image description here

The two isolated nodes on the right are updated to :DELETED

Sample result for iterate function:

╒═════════╤═══════╤═══════════╤═════════════════════╤══════════════════╤═══════════════╤
│"batches"│"total"│"timeTaken"│"committedOperations"│"failedOperations"│"failedBatches"│
╞═════════╪═══════╪═══════════╪═════════════════════╪══════════════════╪═══════════════╪
│1        │2      │0          │2                    │0                 │0              │
│         │       │           │                     │                  │               │
jose_bacoy
  • 12,227
  • 1
  • 20
  • 38
1

The Cypher CASE expression cannot write to the DB.

The following query uses the apoc.do.when procedure instead, which allows you to conditionally execute arbitrary Cypher code if you have up to 2 possible choices (or you can use apoc.do.case for any number of choices). The query also uses OPTIONAL MATCH instead of MATCH for res2 so that the remainder of the query will be executed even when res2 does not exist (i.e., its value is NULL).

MATCH (res:Book) WHERE res.isbn =~ '.*[A-Z].*'
OPTIONAL MATCH (res2:Book) WHERE res2 <> res AND res2.isbn = TOLOWER(res.isbn)
CALL apoc.do.when(res2 IS NULL,
  "SET res.isbn=TOLOWER(res.isbn)",
  "SET res:Deleted",
 {res: res}) YIELD value
RETURN res
cybersam
  • 63,203
  • 6
  • 53
  • 76