String Functions
Every function on this page returns null when any argument is
null, unless the function explicitly documents a different fallback.
String slicing and length helpers count Unicode code points, not UTF-8
bytes. Regex helpers and string.find report Rust regex/string byte
offsets.
Overview
| Goal | Function |
|---|---|
| Case conversion | string.lower, string.upper |
| Case style conversion | string.capitalize, string.case, string.swap_case |
| Trim whitespace | string.trim, string.trim_left, string.trim_right |
| Substring replace | string.replace |
| Count / find text | string.find, string.count, string.before, string.after |
| Substring slice | string.slice |
| Left / right slice | string.prefix, string.suffix |
| Split / join | string.split, string.join, string.words |
| Blank check | string.is_blank |
| Reverse | string.reverse |
| Length | string.length, value.size |
| Pad | string.pad_left, string.pad_right |
| Slug / escape / URL | string.slugify, string.escape, string.url_encode, string.url_decode |
| Normalise Unicode | string.normalize |
| Convert type | toString, toInteger, toFloat, toBoolean |
Predicate in WHERE | STARTS WITH, ENDS WITH, CONTAINS, =~ |
string.lower / string.upper
Unicode case conversion.
RETURN string.lower('Ada LoveLace'); // 'ada lovelace'
RETURN string.upper('ada') // 'ADA'Non-ASCII letters follow Rust's Unicode case mapping:
RETURN string.lower('Ångström') // 'ångström'Case Style
Use string.capitalize(s) for the first character, or
string.capitalize(s, true) to capitalize each whitespace-delimited word.
Use string.case(s, style) when generating identifiers or display text.
RETURN string.capitalize('ada lovelace'); // 'Ada lovelace'
RETURN string.capitalize('ada lovelace', true); // 'Ada Lovelace'
RETURN string.case('hello world', 'camel'); // 'helloWorld'
RETURN string.case('helloWorld', 'snake'); // 'hello_world'
RETURN string.swap_case('LoraDB') // 'lORAdb'Supported string.case styles are 'camel', 'pascal', 'snake',
'kebab', 'screaming_snake' / 'constant', and 'title'.
Case-insensitive matching
MATCH (u:User)
WHERE string.lower(u.email) = string.lower($search)
RETURN uMATCH (u:User)
WHERE string.lower(u.name) STARTS WITH string.lower($prefix)
RETURN ustring.trim / string.trim_left / string.trim_right
Strip whitespace from both ends / left / right.
RETURN string.trim(' hi '); // 'hi'
RETURN string.trim_left(' hi '); // 'hi '
RETURN string.trim_right(' hi ') // ' hi'Common for cleaning up user input before storage:
UNWIND $rows AS row
CREATE (:Contact {email: string.lower(string.trim(row.email))})string.replace
string.replace(str, find, replacement) — replaces every occurrence.
RETURN string.replace('banana', 'a', 'o'); // 'bonono'
RETURN string.replace('hello', 'x', 'y'); // 'hello'
RETURN string.replace('abc def', ' ', '_') // 'abc_def'Multi-step replace
WITH 'Joe O\'Brien' AS raw
RETURN string.replace(string.replace(raw, ' ', '_'), '\'', '') AS slug
// 'Joe_OBrien'string.find / string.count / string.before / string.after
Use these helpers when you need positions or delimiter-based extraction inside one row.
| Function | Behaviour |
|---|---|
string.find(s, needle) | First byte offset, or -1 when missing |
string.find(s, needle, true) | All byte offsets as a list |
string.count(s, needle) | Non-overlapping occurrence count |
string.before(s, needle) | Text before the first occurrence, or null |
string.after(s, needle) | Text after the first occurrence, or null |
RETURN string.find('banana', 'na'); // 2
RETURN string.count('banana', 'na'); // 2
RETURN string.before('a=b=c', '='); // 'a'
RETURN string.after('a=b=c', '='); // 'b=c'
RETURN string.after('abc', '=') // nullRegex patterns can be used with string.count by wrapping the pattern
in slashes:
RETURN string.count('a1 b22 c333', '/\d+/') // 3An empty needle returns null; pass a concrete delimiter or regex so
the count has a clear meaning.
string.slice
string.slice(str, start[, length]) — 0-based indices.
RETURN string.slice('loradb', 0, 4); // 'lora'
RETURN string.slice('loradb', 4); // 'db'
RETURN string.slice('hello', 1, 3) // 'ell'Out-of-range indices return an empty string rather than an error.
RETURN string.slice('hi', 99); // ''
RETURN string.slice('hi', 0, 99) // 'hi'string.prefix / string.suffix
RETURN string.prefix('graphdb', 5); // 'graph'
RETURN string.suffix('graphdb', 2) // 'db'Length exceeding the input returns the whole string:
RETURN string.prefix('ab', 99) // 'ab'string.split / string.join / string.words
RETURN string.split('a,b,c,d', ','); // ['a', 'b', 'c', 'd']
RETURN string.split('one two three', ' '); // ['one', 'two', 'three']
RETURN string.split('x', ','); // ['x']
RETURN string.join(['red', 'green'], ', '); // 'red, green'
RETURN string.words(' red green\tblue ') // ['red', 'green', 'blue']Empty input returns [''].
string.words uses Unicode whitespace and drops empty fields, which is
usually what you want for tokenizing human-entered text.
Split + UNWIND
Turn comma-separated values into rows:
UNWIND string.split('red,green,blue', ',') AS color
CREATE (:Swatch {color: color})Join values for display
string.join(list, separator) accepts strings, numbers, booleans, and
null values. null becomes an empty field.
MATCH (u:User)
RETURN u.name, string.join(u.tags, ', ') AS tags_csvstring.reverse / value.reverse
Works on both strings and lists.
RETURN string.reverse('hello'); // 'olleh'
RETURN value.reverse([1, 2, 3]) // [3, 2, 1]reverse(x) is a compatibility alias for value.reverse(x), which
works for both strings and lists. Use string.reverse(s) when you want
to be explicit that the input should be text.
string.length / value.size
| Function | Measures |
|---|---|
string.length(s) | Unicode code-point count |
value.size(s) / size(s) | Polymorphic size helper; strings return their length |
path.length(p) / length(p) | Hop count for paths, not a string helper |
RETURN string.length('abc'); // 3
RETURN string.length('café'); // 4
RETURN value.size('abc') // 3For paths, use path.length(p).
string.is_blank
string.is_blank(s) returns true when a string is empty or contains
only whitespace. It is useful for imports where a missing field arrives
as spaces instead of null.
RETURN string.is_blank(' '); // true
RETURN string.is_blank('\t\n'); // true
RETURN string.is_blank(' data ') // falsestring.pad_left / string.pad_right
string.pad_left(str, length, padding) / string.pad_right(str, length, padding) — pads to
the target length using the padding character repeated.
RETURN string.pad_left('7', 3, '0'); // '007'
RETURN string.pad_right('7', 3, '0'); // '700'
RETURN string.pad_left('abc', 5, '.'); // '..abc'
RETURN string.pad_right('abc', 5, '.') // 'abc..'If the input is already longer than length, it's returned unchanged.
Fixed-width formatting
MATCH (r:Record)
RETURN string.pad_left(toString(r.id), 6, '0') AS padded_idEncoding and Escaping
Use string.slugify for simple URL slugs, string.escape when embedding
text into another format, and URL helpers for query-string safe values.
RETURN string.slugify('Hello, World! 2026'); // 'hello-world-2026'
RETURN string.escape('Tom & "Ada"', 'html'); // 'Tom & "Ada"'
RETURN string.escape('Tom & "Ada"', 'json'); // '"Tom & \"Ada\""'
RETURN string.url_encode('a b/c'); // 'a%20b%2Fc'
RETURN string.url_decode('a%20b%2Fc') // 'a b/c'string.escape supports 'json', 'html', and 'cypher' / 'lora'.
string.slugify is intentionally conservative: it lowercases ASCII
letters and collapses non-alphanumeric runs to -.
string.normalize
string.normalize(s[, form]) applies Unicode normalization. The default
form is 'nfc'. Supported forms are 'nfc', 'nfd', 'nfkc', and
'nfkd'.
RETURN string.normalize('Café'); // 'Café' (NFC)
RETURN string.length(string.normalize('é', 'nfd')) // 2Normalize text before storing it when users may submit visually identical
strings in different Unicode forms. Pair with string.lower and
string.trim for stable email or slug comparisons.
Type conversion
These helpers are kept for Cypher compatibility and quick scalar
parsing. For explicit typed construction, prefer casts:
'2024-01-15'::DATE, {x: 1, y: 2}::POINT,
[1, 2, 3]::VECTOR<INTEGER>(3), or CAST(value AS TYPE).
Use TRY_CAST(value AS TYPE) when invalid input should become null.
| Function | Accepts | Returns |
|---|---|---|
toString(x) | any | String; null → null |
toInteger(x) / toIntegerOrNull(x) | Int, Float (truncates), String, Bool | Int; OrNull form returns null on parse failure |
toFloat(x) / toFloatOrNull(x) | Int, Float, String | Float; OrNull form returns null on parse failure |
toBoolean(x) / toBooleanOrNull(x) | Bool, String ("true"/"false"), Int (0 / non-0) | Bool; OrNull form returns null on parse failure |
RETURN toString(42); // '42'
RETURN toString(true); // 'true'
RETURN toString('2024-01-15'::DATE); // '2024-01-15'
RETURN toInteger('007'); // 7
RETURN toInteger(3.9); // 3 (truncates)
RETURN toInteger(true); // 1
RETURN toIntegerOrNull('not a number'); // null (parse fails)
RETURN toFloat('3.14'); // 3.14
RETURN toFloat(42); // 42.0
RETURN toBoolean('TRUE'); // true
RETURN toBoolean(0); // false
RETURN toBooleanOrNull('maybe') // nullSafe conversion pattern
Combine with coalesce for a
default on parse failure:
MATCH (p:Product) RETURN coalesce(toInteger(p.stock), 0) AS stockFor imports where the target type is not one of the simple scalar helper names, keep the conversion explicit:
UNWIND $rows AS row
WITH row, TRY_CAST(row.shipped_on AS DATE) AS shipped_on
WHERE shipped_on IS NOT NULL
CREATE (:Shipment {id: row.id, shipped_on: shipped_on})String operators (in WHERE)
Covered in the WHERE page —
included here for completeness:
| Operator | Case-sensitive | Description |
|---|---|---|
STARTS WITH | yes | Prefix match |
ENDS WITH | yes | Suffix match |
CONTAINS | yes | Substring match |
=~ | yes | Regex match (Rust regex, RE2-style — no backreferences) |
MATCH (u:User) WHERE u.email ENDS WITH '@loradb.com' RETURN u;
MATCH (u:User) WHERE string.lower(u.email) =~ '.*@loradb\\.com$' RETURN u;
MATCH (u:User) WHERE u.name CONTAINS 'Admin' RETURN uRegex vs CONTAINS
Regex is more expressive but slower and strict-anchored (=~ 'foo'
matches only the full string foo). Prefer CONTAINS for simple
substring matches.
Common patterns
Slugify
WITH 'Hello, World! 2024' AS raw
RETURN string.slugify(raw) AS slug
// 'hello-world-2024'For international slugs, normalize first and decide host-side whether to transliterate non-ASCII characters.
Initials
MATCH (p:Person) WHERE p.name IS NOT NULL
RETURN p.name,
reduce(acc = '', part IN string.split(p.name, ' ') |
acc + string.prefix(part, 1)) AS initialsDomain from email
MATCH (u:User) WHERE u.email CONTAINS '@'
RETURN u.email,
string.slice(u.email, value.size(string.split(u.email, '@')[0]) + 1) AS domainNormalise for comparison
MATCH (u:User)
WHERE string.lower(string.trim(u.email)) = string.lower(string.trim($candidate))
RETURN uJoin a list into a string
MATCH (u:User)
RETURN u.name, string.join(u.tags, ', ') AS tags_csvFor conditional joins or per-element formatting, use
reduce so each element can be transformed before it
is appended.
Parse key=value pairs
WITH 'a=1;b=2;c=3' AS s
RETURN reduce(
m = {},
pair IN string.split(s, ';') |
m + {[string.split(pair, '=')[0]]: string.split(pair, '=')[1]}
) AS parsed
// {a: '1', b: '2', c: '3'}Values are strings — wrap each with
toInteger if you need numeric
types.
Truncate for preview
MATCH (p:Post)
RETURN p.id,
CASE WHEN string.length(p.body) > 100
THEN string.prefix(p.body, 97) + '...'
ELSE p.body
END AS previewThe conditional here is a CASE
expression — LoraDB's ternary. See that page for the full reference.
Limitations
string.lower/string.upperuse Unicode case mapping, not locale-specific case folding. Turkish dotted/dotlessiand similar locale-sensitive cases should still be handled host-side when exact locale behavior matters.string.findreturns byte offsets. Usestring.slicefor code-point slicing once you already know the desired character positions.string.normalizehandles Unicode normalization forms, but it is not a locale-aware collation or fuzzy matching function.- Use
string.lengthwhen you need Unicode code-point counts.
See also
- Scalars → String — literal syntax and comparison.
- WHERE → String matching.
- Lists —
string.splitreturns a list. - Functions → Overview —
toString,toInteger, etc.