ZhangZhihui's Blog  

Values and types

Property types

A property type value is one that can be stored as a node or relationship property.

Property types are the most primitive types in Cypher and include the following: 

  • BOOLEAN
  • DATE
  • DURATION
  • FLOAT
  • INTEGER
  • LIST
  • LOCAL DATETIME
  • LOCAL TIME
  • POINT
  • STRING
  • ZONED DATETIME
  • ZONED TIME

Structural types

The following data types are included in the structural types category: 

  • NODE
  • RELATIONSHIP
  • PATH

Constructed types

The following data types are included in the constructed types category: 

  • LIST
  • MAP

Types and their synonyms

TypeSynonyms

ANY

ANY VALUE

BOOLEAN

BOOL

DATE

 

DURATION

 

FLOAT

 

INTEGER

INTSIGNED INTEGER

LIST<INNER_TYPE>

ARRAY<INNER_TYPE>INNER_TYPE LISTINNER_TYPE ARRAY

LOCAL DATETIME

TIMESTAMP WITHOUT TIME ZONETIMESTAMP WITHOUT TIMEZONE

LOCAL TIME

TIME WITHOUT TIME ZONETIME WITHOUT TIMEZONE

MAP

 

NODE

ANY NODEVERTEXANY VERTEX

NOTHING

 

NULL

 

PATH

 

POINT

 

PROPERTY VALUE

ANY PROPERTY VALUE

RELATIONSHIP

ANY RELATIONSHIPEDGEANY EDGE

STRING

VARCHAR

ZONED DATETIME

TIMESTAMP WITH TIME ZONETIMESTAMP WITH TIMEZONE

ZONED TIME

TIME WITH TIME ZONETIME WITH TIMEZONE

INNER_TYPE_1 | INNER_TYPE_2…​

ANY<INNER_TYPE_1 | INNER_TYPE_2…​>

All Cypher types contain the null value. To make them not nullable, NOT NULL can be appended to the end of the type (e.g. BOOLEAN NOT NULLLIST<FLOAT NOT NULL>). A shorthand syntax equivalent, introduced in Neo4j 5.14, for NOT NULL is to use an exclamation mark ! (e.g. INTEGER!LIST<STRING!>). Note that closed dynamic types (INNER_TYPE_1 | INNER_TYPE_2…​) cannot be appended with NOT NULL: all inner types must be nullable, or all appended with NOT NULL.

Type Normalization

Cypher runs a normalization algorithm on all input types, simplifying the given type to a deterministic representation for equivalent types. Types are simplified to their default name (e.g. BOOL is simplified to BOOLEAN). Encompassing types are absorbed (e.g. LIST<BOOLEAN> | LIST<BOOLEAN | INTEGER> is normalized to LIST<BOOLEAN | INTEGER>). Types are also ordered.

The type PROPERTY VALUE is expanded to a closed dynamic union of all valid property types, and if all types are represented, then the normalization would simplify to ANY.

For example, given the closed dynamic type BOOL | LIST<INT> | BOOLEAN | LIST<FLOAT | INT>, the normalized type would be: BOOLEAN | LIST<INTEGER | FLOAT>.

This normalization is run on types used in type predicate expressions, and in property type constraints. Type normalization is also used to ensure the consistency of the output for the valueType() function.

Ordering of types

The ordering of types is as follows:

  • Predefined types

    • NOTHING

    • NULL

    • BOOLEAN

    • STRING

    • INTEGER

    • FLOAT

    • DATE

    • LOCAL TIME

    • ZONED TIME

    • LOCAL DATETIME

    • ZONED DATETIME

    • DURATION

    • POINT

    • NODE

    • RELATIONSHIP

  • Constructed types

    • MAP

    • LIST<INNER_TYPE> (ordered by the inner type)

    • PATH

  • Dynamic union types

    • INNER_TYPE_1 \| INNER_TYPE_2…​ (ordered by specific rules for closed dynamic union type)

    • ANY

Subtypes are always ordered before any enclosing types (e.g. LIST<INTEGER> is ordered before LIST<INTEGER | FLOAT>). This also means that the NOT NULL variants of each type comes before the nullable variant.

The order between two closed dynamic unions A and B is determined as followed:

  • If A has fewer inner types than BA is ordered first.

  • If A and B have the same number of inner types, they are ordered according to the order of the first inner type that differ (lexicographic order).

The resulting order is deterministic.

Property type details

The below table provides more detailed information about the various property types that Cypher supports. Note that Cypher types are implemented using Java, and that below table references Java value constants.

TypeMin. valueMax. valuePrecision

BOOLEAN

False

True

-

DATE

-999_999_999-01-01

+999_999_999-12-31

Days

DURATION

P-292471208677Y-6M-15DT-15H-36M-32S

P292471208677Y6M15DT15H36M32.999999999S

Nanoseconds

FLOAT

Double.MIN_VALUE [1]

Double.MAX_VALUE

64 bit

INTEGER

Long.MIN_VALUE

Long.MAX_VALUE

64 bit

LOCAL DATETIME

-999_999_999-01-01T00:00:00

+999_999_999-12-31T23:59:59.999999999

Nanoseconds

LOCAL TIME

00:00:00

23:59:59.999999999

Nanoseconds

POINT

Cartesian: (-Double.MAX_VALUE-Double.MAX_VALUE)

Cartesian_3D: (-Double.MAX_VALUE-Double.MAX_VALUE-Double.MAX_VALUE)

WGS_84: (-180-90)

WGS_84_3D: (-180-90-Double.MAX_VALUE)

Cartesian: (Double.MAX_VALUEDouble.MAX_VALUE)

Cartesian_3D: (Double.MAX_VALUEDouble.MAX_VALUEDouble.MAX_VALUE)

WGS_84: (18090)

WGS_84_3D: (18090Double.MAX_VALUE)

The precision of each coordinate of the POINT is 64 bit as they are floats.

STRING

-

-

-

ZONED DATETIME

-999_999_999-01-01T00:00:00+18:00

+999_999_999-12-31T23:59:59.999999999-18:00

Nanoseconds

ZONED TIME

00:00:00+18:00

23:59:59.999999999-18:00

Nanoseconds

Java value details

NameValue

Double.MAX_VALUE

1.7976931348623157e+308

Double.MIN_VALUE

4.9e-324

Long.MAX_VALUE

2^63-1

Long.MIN_VALUE

-2^63

 

Temporal values

DATELOCAL TIMEZONED TIMELOCAL DATETIME, and ZONED DATETIME are temporal instant types. A temporal instant value expresses a point in time with varying degrees of precision.

By contrast, DURATION is not a temporal instant type. A DURATION represents a temporal amount, capturing the difference in time between two instants, and can be negative. DURATION captures the amount of time between two instants, it does not capture a start time and end time.

Starting from Neo4j 5.9, some temporal types have been renamed. The table below shows the current as well as the old names of the temporal types.

TypeOld type name

DATE

Date

LOCAL TIME

LocalTime

ZONED TIME

Time

LOCAL DATETIME

LocalDateTime

ZONED DATETIME

DateTime

DURATION

Duration

Spatial values

The POINT type

Neo4j supports the POINT type for values of spatial geometry.

Values with the POINT type have the following characteristics:

  • Each point can have either 2 or 3 dimensions. This means it contains either 2 or 3 64-bit FLOAT values, which together are called the Coordinate.

  • Each point will also be associated with a specific Coordinate Reference System (CRS) that determines the meaning of the values in the Coordinate.

  • Instances of POINT and LIST<POINT> can be assigned to node and relationship properties.

  • Nodes and relationships with POINT or LIST<POINT> properties can be indexed using a point index. This is true for all CRSs (and for both 2D and 3D).

  • The distance function will work on points in all CRS and in both 2D and 3D, but only if the two points have the same CRS (and therefore also same dimension).

Coordinate Reference Systems

Four Coordinate Reference Systems (CRS) are supported, each of which falls within one of two types: geographic coordinates, modeling points on the earth, or Cartesian coordinates, modeling points in euclidean space:

Data within different coordinate systems are entirely incomparable, and cannot be implicitly converted from one to the other. This is true even if they are both Cartesian or both geographic but of a different dimension. For example, if you search for 3D points using a 2D range, you will get no results. However, they can be ordered, as discussed in more detail in the section about ordering and comparison of values.

Geographic coordinate reference systems

Two Geographic Coordinate Reference Systems (CRS) are supported, modeling points on the earth:

  • WGS 84 2D

    • A 2D geographic point in the WGS 84 CRS is specified in one of two ways:

      • longitude and latitude (if these are specified, and the crs is not, then the crs is assumed to be WGS-84).

      • x and y (in this case the crs must be specified, or will be assumed to be Cartesian).

    • Specifying this CRS can be done using either the name 'wgs-84' or the SRID 4326 as described in point() - WGS 84 2D.

  • WGS 84 3D

    • A 3D geographic point in the WGS 84 CRS is specified one of in two ways:

      • longitudelatitude and either height or z (if these are specified, and the crs is not, then the crs is assumed to be WGS-84-3D).

      • xy and z (in this case the crs must be specified, or will be assumed to be Cartesian-3D).

    • Specifying this CRS can be done using either the name 'wgs-84-3d' or the SRID 4979 as described in point() - WGS 84 3D.

Converting coordinate units

The units of the latitude and longitude fields are in decimal degrees, and need to be specified as floating point numbers using Cypher literals. It is not possible to use any other format, such as 'degrees, minutes, seconds'. The units of the height field are in meters. When geographic points are passed to the distance function, the result will always be in meters. If the coordinates are in any other format or unit than those supported, it is necessary to explicitly convert them.

For example, if the incoming $height is a STRING field in kilometers, it would be necessary to add height: toFloat($height) * 1000 to the query. Likewise if the results of the distance function are expected to be returned in kilometers, an explicit conversion is required. The below query is an example of this conversion:

WITH
  point({latitude: toFloat('13.43'), longitude: toFloat('56.21')}) AS p1,
  point({latitude: toFloat('13.10'), longitude: toFloat('56.41')}) AS p2
RETURN toInteger(point.distance(p1, p2)/1000) AS km

Cartesian coordinate reference systems

Two Cartesian Coordinate Reference Systems (CRS) are supported, modeling points in euclidean space:

  • Cartesian 2D

    • A 2D point in the Cartesian CRS is specified with a map containing x and y coordinate values

    • Specifying this CRS can be done using either the name 'cartesian' or the SRID 7203 as described in point() - Cartesian 2D

  • Cartesian 3D

    • A 3D point in the Cartesian CRS is specified with a map containing xy and z coordinate values

    • Specifying this CRS can be done using either the name 'cartesian-3d' or the SRID 9157 as described in point() - Cartesian 3D)

The units of the xy, and z fields are unspecified. This means that when two Cartesian points are passed to the distance function, the resulting value will be in the same units as the original coordinates. This is true for both 2D and 3D points, as the Pythagoras equation used is generalized to any number of dimensions. However, just as you cannot compare geographic points to Cartesian points, you cannot calculate the distance between a 2D point and a 3D point. If you need to do that, explicitly transform the one type into the other. For example:

WITH
  point({x: 3, y: 0}) AS p2d,
  point({x: 0, y: 4, z: 1}) AS p3d
RETURN
  point.distance(p2d, p3d) AS bad,
  point.distance(p2d, point({x: p3d.x, y: p3d.y})) AS good

Spatial instants

All POINT types are created from two components:

  • The Coordinate containing either 2 or 3 FLOAT values (64-bit).

  • The Coordinate Reference System (or CRS) defining the meaning (and possibly units) of the values in the Coordinate.

For most use cases, it is not necessary to specify the CRS explicitly as it will be deduced from the keys used to specify the coordinate. Two rules are applied to deduce the CRS from the coordinate:

  • Choice of keys:

    • If the coordinate is specified using the keys latitude and longitude the CRS will be assumed to be Geographic and therefor either WGS-84 or WGS-84-3D.

    • If instead x and y are used, then the default CRS would be Cartesian or Cartesian-3D.

  • Number of dimensions:

    • If there are 2 dimensions in the coordinate, x & y or longitude & latitude the CRS will be a 2D CRS.

    • If there is a third dimensions in the coordinate, z or height the CRS will be a 3D CRS.

All fields are provided to the point function in the form of a map of explicitly named arguments. Neo4j does not support an ordered list of coordinate fields because of the contradictory conventions between geographic and cartesian coordinates, where geographic coordinates normally list y before x (latitude before longitude).

The following query which returns points created in each of the four supported CRSs. Take particular note of the order and keys of the coordinates in the original point function, and how those values are displayed in the results:

RETURN
  point({x: 3, y: 0}) AS cartesian_2d,
  point({x: 0, y: 4, z: 1}) AS cartesian_3d,
  point({latitude: 12, longitude: 56}) AS geo_2d,
  point({latitude: 12, longitude: 56, height: 1000}) AS geo_3d

 

╒════════════════════════════╤═════════════════════════════════╤══════════════════════════════╤══════════════════════════════════════╕
│cartesian_2d                │cartesian_3d                     │geo_2d                        │geo_3d                                │
╞════════════════════════════╪═════════════════════════════════╪══════════════════════════════╪══════════════════════════════════════╡
│point({srid:7203, x:3, y:0})│point({srid:9157, x:0, y:4, z:1})│point({srid:4326, x:56, y:12})│point({srid:4979, x:56, y:12, z:1000})│
└────────────────────────────┴─────────────────────────────────┴──────────────────────────────┴──────────────────────────────────────┘

For the geographic coordinates, it is important to note that the latitude value should always lie in the interval [-90, 90]. Any other value outside this range will throw an exception. The longitude value should always lie in the interval [-180, 180]. Any other value outside this range will be wrapped around to fit in this range. The height value and any Cartesian coordinates are not explicitly restricted. Any value within the allowed range of the signed 64-bit floating point type will be accepted.

Components of points

Components of POINT values can be accessed as properties.

Component

instant.x

instant.y

instant.z

instant.longitude

instant.latitude

instant.height

instant.crs

instant.srid

Spatial values and indexes

If there is a range or point index on a particular node or relationship property, and a spatial point is assigned to that property on a node or relationship, the node or relationship will be indexed.

In a point index, Neo4j uses space filling curves in 2D or 3D over an underlying generalized B+Tree. Point indexes are optimized for distance and bounding box queries. For more information, see Managing indexes → Point indexes.

In a range index, the points will be sorted according to their lexicographic ordering per coordinate reference system. For point values, this index has support for equality checks. For more information, see Managing indexes → Range indexes.

Comparability and orderability

Cypher does not support comparing spatial values using the inequality operators, <<=>, and >=. Attempting to do so will return null.

To compare spatial points within a specific range, instead use the spatial functions point.distance or point.withinBBox.

Working with null

In Cypher®, null is used to represent missing or undefined values. All data types in Cypher are nullable. This means that type predicate expressions always return true for null values.

Conceptually, null means a missing or unknown value, and it is treated somewhat differently from other values. For example, returning a property from a node that does not have said property produces null. Most expressions that take null as input will produce null. In the case of a predicate used in a WHERE clause, anything that is not true is interpreted as being false.

null is not equal to null. Not knowing two values does not imply that they are the same value. This means that the expression null = null yields null, and not true.

Logical operations with null

The logical operators (ANDORXORNOT) treat null as the unknown value of three-valued logic.

Table 1. Truth table for logical operators
abAND bOR bXOR bNOT a

false

false

false

false

false

true

false

null

false

null

null

true

false

true

false

true

true

true

true

false

false

true

true

false

true

null

null

true

null

false

true

true

true

true

false

false

null

false

false

null

null

null

null

null

null

null

null

null

null

true

null

true

null

null

The IN operator and null

The IN operator follows similar logic. If Cypher can ascertain that something exists in a list, the result will be true. Any list that contains a null and does not have a matching element will return null. Otherwise, the result will be false.

Table 2. examples of expressions containing the IN operator
ExpressionResult

2 IN [1, 2, 3]

true

2 IN [1, null, 3]

null

2 IN [1, 2, null]

true

2 IN [1]

false

2 IN []

false

null IN [1, 2, 3]

null

null IN [1, null, 3]

null

null IN []

false

Using allanynone, and single follows a similar rule. If the result can be calculated definitively, true or false is returned. Otherwise null is produced.

The [] operator and null

Accessing a list or a map with null will result in null:

ExpressionResult

[1, 2, 3][null]

null

[1, 2, 3, 4][null..2]

null

[1, 2, 3][1..null]

null

{age: 25}[null]

null

Using parameters to pass in the bounds, such as a[$lower..$upper], may result in a null for the lower or upper bound (or both). The following workaround will prevent this from happening by setting the absolute minimum and maximum bound values: 

a[coalesce($lower,0)..coalesce($upper,size(a))]

Expressions that return null

  • Getting a missing element from a list: [][0]head([]).

  • Trying to access a property that does not exist on a node or relationship: n.missingProperty.

  • Comparisons when either side is null1 < null.

  • Arithmetic expressions containing null1 + null.

  • Some function calls where any argument is null: e.g., sin(null).

Using IS NULL and IS NOT NULL

Testing any value against null, either with the = operator or with the <> operator, always evaluates to null. Therefore, use the special equality operators IS NULL or IS NOT NULL.

 

Lists

Cypher® includes comprehensive support for lists. 

List range and size

The below examples use the range function to create lists. This function returns a list containing all numbers between given start and end numbers. The range is inclusive in both ends.

RETURN range(0, 10) AS list

 

╒══════════════════════════════════╕
│list                              │
╞══════════════════════════════════╡
│[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]│
└──────────────────────────────────┘

It is possible to use negative numbers, to start from the end of the list instead.

RETURN range(0, 10)[3] AS element1, range(0, 10)[-3] AS element2

 

╒════════╤════════╕
│element1│element2│
╞════════╪════════╡
│3       │8       │
└────────┴────────┘

Finally, it is possible to use ranges inside the brackets to return ranges of the list. The list range operator ([]) is inclusive of the first value, but exclusive of the last value.

RETURN range(0, 10)[0..3] AS list

 

╒═════════╕
│list     │
╞═════════╡
│[0, 1, 2]│
└─────────┘

Pattern comprehension

Pattern comprehension is a syntactic construct available in Cypher for creating a list based on matchings of a pattern. A pattern comprehension matches the specified pattern like a normal MATCH clause, with predicates like a normal WHERE clause, but yields a custom projection as specified.

CREATE
  (keanu:Person {name: 'Keanu Reeves'}),
  (johnnyMnemonic:Movie {title: 'Johnny Mnemonic', released: 1995}),
  (theMatrixRevolutions:Movie {title: 'The Matrix Revolutions', released: 2003}),
  (theMatrixReloaded:Movie {title: 'The Matrix Reloaded', released: 2003}),
  (theReplacements:Movie {title: 'The Replacements', released: 2000}),
  (theMatrix:Movie {title: 'The Matrix', released: 1999}),
  (theDevilsAdvocate:Movie {title: 'The Devils Advocate', released: 1997}),
  (theMatrixResurrections:Movie {title: 'The Matrix Resurrections', released: 2021}),
  (keanu)-[:ACTED_IN]->(johnnyMnemonic),
  (keanu)-[:ACTED_IN]->(theMatrixRevolutions),
  (keanu)-[:ACTED_IN]->(theMatrixReloaded),
  (keanu)-[:ACTED_IN]->(theReplacements),
  (keanu)-[:ACTED_IN]->(theMatrix),
  (keanu)-[:ACTED_IN]->(theDevilsAdvocate),
  (keanu)-[:ACTED_IN]->(theMatrixResurrections)

Examples

This example returns a list that contains the year when the movies were released. The pattern matching in the pattern comprehension looks for Matrix in the movie title and that the node keanu (Person node with the name Keanu Reeves) has a relationship with the movie.

MATCH (keanu:Person {name: 'Keanu Reeves'})
RETURN [(keanu)-->(b:Movie) WHERE b.title CONTAINS 'Matrix' | b.released] AS years

 

╒════════════════════════╕
│years                   │
╞════════════════════════╡
│[2003, 2003, 1999, 2021]│
└────────────────────────┘

List comprehension

List comprehension is a syntactic construct available in Cypher for creating a list based on existing lists.

 

List comprehension follows the form of the mathematical set-builder notation (set comprehension) instead of the use of map and filter functions.

RETURN [x IN range(0,10) WHERE x % 2 = 0 | x^3 ] AS result

 

╒══════════════════════════════════════╕
│result                                │
╞══════════════════════════════════════╡
│[0.0, 8.0, 64.0, 216.0, 512.0, 1000.0]│
└──────────────────────────────────────┘

Either the WHERE part, or the expression, can be omitted, if you only want to filter or map respectively.

RETURN [x IN range(0,10) WHERE x % 2 = 0 ] AS result

 

╒═══════════════════╕
│result             │
╞═══════════════════╡
│[0, 2, 4, 6, 8, 10]│
└───────────────────┘

 

RETURN [x IN range(0,10) | x^3 ] AS result

 

╒══════════════════════════════════════════════════════════════════════╕
│result                                                                │
╞══════════════════════════════════════════════════════════════════════╡
│[0.0, 1.0, 8.0, 27.0, 64.0, 125.0, 216.0, 343.0, 512.0, 729.0, 1000.0]│
└──────────────────────────────────────────────────────────────────────┘

 

Maps

Literal maps

RETURN {key: 'Value', listKey: [{inner: 'Map1'}, {inner: 'Map2'}]} AS map

Map projection

Cypher supports map projections, which allows for the construction of map projections from nodes, relationships, and other map values.

A map projection begins with the variable bound to the graph entity to be projected from, and contains a body of comma-separated map elements, enclosed by { and }.

map_variable {map_element, [, ...n]}

A map element projects one or more key-value pairs to the map projection. There exist four different types of map projection elements:

  • Property selector - Projects the property name as the key, and the value from the map_variable as the value for the projection.

  • Literal entry - This is a key-value pair, with the value being an arbitrary expression key: <expression>.

  • Variable selector - Projects a variable, with the variable name as the key, and the value the variable is pointing to as the value of the projection. Its syntax is just the variable.

  • All-properties selector - projects all key-value pairs from the map_variable value.

The following conditions apply:

  • If the map_variable points to a null value, the whole map projection will evaluate to null.

  • The key names in a map must be of type STRING.

CREATE
  (keanu:Person {name: 'Keanu Reeves', nationality: 'Canadian'}),
  (carrieAnne:Person {name: 'Carrie-Anne Moss'}),
  (theMatrixRevolutions:Movie {title: 'The Matrix Revolutions', released: 2003}),
  (theMatrixReloaded:Movie {title: 'The Matrix Reloaded', released: 2003}),
  (theMatrix:Movie {title: 'The Matrix', released: 1999}),
  (theDevilsAdvocate:Movie {title: 'The Devils Advocate', released: 1997}),
  (theMatrixResurrections:Movie {title: 'The Matrix Resurrections', released: 2021}),
  (keanu)-[:ACTED_IN]->(theMatrix),
  (keanu)-[:ACTED_IN]->(theMatrixRevolutions),
  (keanu)-[:ACTED_IN]->(theMatrixReloaded),
  (keanu)-[:ACTED_IN]->(theMatrixResurrections),
  (keanu)-[:ACTED_IN]->(theDevilsAdvocate),
  (carrieAnne)-[:ACTED_IN]->(theMatrix),
  (carrieAnne)-[:ACTED_IN]->(theMatrixRevolutions),
  (carrieAnne)-[:ACTED_IN]->(theMatrixReloaded),
  (carrieAnne)-[:ACTED_IN]->(theMatrixResurrections)

Examples

The below query finds the Keanu Reeves node and the movies he has acted in. It is an example of a map projection with a literal entry, which in turn also uses map projection with a property selector inside the aggregating collect() function.

MATCH (keanu:Person {name: 'Keanu Reeves'})-[:ACTED_IN]->(movie:Movie)
WITH keanu, collect(movie{.title, .released}) AS movies
RETURN keanu{.name, movies: movies}

 

╒══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╕
│keanu                                                                                                                                         │
╞══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╡
│{name: "Keanu Reeves", movies: [{released: 2003, title: "The Matrix Revolutions"}, {released: 2003, title: "The Matrix Reloaded"}, {released: │
│1999, title: "The Matrix"}, {released: 1997, title: "The Devils Advocate"}, {released: 2021, title: "The Matrix Resurrections"}]}             │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

The below query finds all Person nodes in the graph that have one or more relationships with the type ACTED_IN connected to Movie nodes. It uses the count() function to count how many Movie nodes are connected to each Person node in this way, and uses a variable selector to project the value of the count.

MATCH (actor:Person)-[:ACTED_IN]->(movie:Movie)
WITH actor, count(movie) AS numberOfMovies
RETURN actor{.name, numberOfMovies}

 

╒═════════════════════════════════════════════╕
│actor                                        │
╞═════════════════════════════════════════════╡
│{name: "Keanu Reeves", numberOfMovies: 5}    │
├─────────────────────────────────────────────┤
│{name: "Carrie-Anne Moss", numberOfMovies: 4}│
└─────────────────────────────────────────────┘

The below query returns all properties from the Keanu Reeves node. An all-properties selector is used to project all the node properties, and additionally, explicitly project the property age. Since this property does not exist on the node Keanu Reeves, a null value is projected instead.

MATCH (keanu:Person {name: 'Keanu Reeves'})
RETURN keanu{.*, .age}

 

╒══════════════════════════════════════════════════════════╕
│keanu                                                     │
╞══════════════════════════════════════════════════════════╡
│{nationality: "Canadian", age: null, name: "Keanu Reeves"}│
└──────────────────────────────────────────────────────────┘

The below query is an example of statically accessing individual map members using the . operator:

WITH {age: 58, profession: 'Actor'} as keanuStats
RETURN keanuStats.profession AS profession

 

Casting data values

Cypher® supports a number of functions to cast values to different data types. 

Functions for converting data values

FunctionDescription

toBoolean()

Converts a STRINGINTEGER, or BOOLEAN value to a BOOLEAN value.

toBooleanList()

Converts a LIST<ANY> and returns a LIST<BOOLEAN> values. If any values are not convertible to BOOLEAN they will be null in the LIST<BOOLEAN> returned.

toBooleanOrNull()

Converts a STRINGINTEGER or BOOLEAN value to a BOOLEAN value. For any other input value, null will be returned.

toFloat()

Converts an INTEGERFLOAT, or a STRING value to a FLOAT value. 

toFloatList()

Converts a LIST<ANY> and returns a LIST<FLOAT> values. If any values are not convertible to FLOAT they will be null in the LIST<FLOAT> returned.

toFloatOrNull()

Converts an INTEGERFLOAT, or a STRING value to a FLOAT. For any other input value, null will be returned.

toInteger()

Converts a BOOLEANINTEGERFLOAT or a STRING value to an INTEGER value.

toIntegerList()

Converts a LIST<ANY> to a LIST<INTEGER> values. If any values are not convertible to INTEGER they will be null in the LIST<INTEGER> returned.

toIntegerOrNull()

Converts a BOOLEANINTEGERFLOAT or a STRING value to an INTEGER value. For any other input value, null will be returned.

toString()

Converts an INTEGERFLOATBOOLEANSTRINGPOINTDURATIONDATEZONED TIMELOCAL TIMELOCAL DATETIME, or ZONED DATETIME value to a STRING value.

toStringList()

Converts a LIST<ANY> and returns a LIST<STRING> values. If any values are not convertible to STRING they will be null in the LIST<STRING> returned.

toStringOrNull()

Converts an INTEGERFLOATBOOLEANSTRINGPOINTDURATIONDATEZONED TIMELOCAL TIMELOCAL DATETIME, or ZONED DATETIME value to a STRING. For any other input value, null will be returned.

 

WITH date({
  year: 2023, month: 5, day: 2
}) AS d
RETURN toFloat(d)

 

However, if the same value is passed to the function toFloatOrNullnull will be returned.

WITH date({
  year: 2023, month: 5, day: 2
}) AS d
RETURN toFloatOrNull(d)

 

╒════════════════╕
│toFloatOrNull(d)│
╞════════════════╡
│null            │
└────────────────┘

 

Type predicate expressions

A type predicate expression can be used to verify the type of a variable, literal, property or other Cypher® expression.

Syntax

<expr> IS :: <TYPE>

Verify the type of a Cypher expression

UNWIND [42, true, 'abc', null] AS val
RETURN val, val IS :: INTEGER AS isInteger

 

╒═════╤═════════╕
│val  │isInteger│
╞═════╪═════════╡
│42   │true     │
├─────┼─────────┤
│true │false    │
├─────┼─────────┤
│"abc"│false    │
├─────┼─────────┤
│null │true     │
└─────┴─────────┘

Type predicate expressions with NOT

It is also possible to verify that a Cypher expression is not of a certain type, using the negated type predicate expression IS NOT ::.

UNWIND [42, true, 'abc', null] AS val
RETURN val, val IS NOT :: STRING AS notString

 

╒═════╤═════════╕
│val  │notString│
╞═════╪═════════╡
│42   │true     │
├─────┼─────────┤
│true │true     │
├─────┼─────────┤
│"abc"│false    │
├─────┼─────────┤
│null │false    │
└─────┴─────────┘

Type predicate expressions for null

All Cypher types includes the null value. Since Neo4j 5.10, type predicate expressions can be appended with NOT NULL. This means that IS :: returns true for all expressions evaluating to null, unless NOT NULL is appended.

RETURN
  null IS :: BOOLEAN AS isBoolean,
  null IS :: BOOLEAN NOT NULL AS isNotNullBoolean

 

╒═════════╤════════════════╕
│isBoolean│isNotNullBoolean│
╞═════════╪════════════════╡
│true     │false           │
└─────────┴────────────────┘

Likewise, IS NOT :: returns false for all expressions evaluating to null, unless the type is appended with NOT NULL.

RETURN
  (null + 1) IS NOT :: DATE AS isNotDate,
  (null + 1) IS NOT :: DATE NOT NULL AS isNotNotNullDate

 

╒═════════╤════════════════╕
│isNotDate│isNotNotNullDate│
╞═════════╪════════════════╡
│false    │true            │
└─────────┴────────────────┘

It is also possible to check whether a value is the only null value using the NULL type.

RETURN null IS :: NULL AS isNull

 

╒══════╕
│isNull│
╞══════╡
│true  │
└──────┘

Closed dynamic union types (INNER_TYPE_1 | INNER_TYPE_2…​) cannot be declared as NOT NULL. Instead, all the inner types should be individually declared as not nullable to achieve this behavior.

Note that all inner types in a closed dynamic union must be either nullable, or not nullable. This is because null values cannot be attributed to a specific type. A syntax error will be raised if the inner types are not of the same nullability.

RETURN 1 IS :: INTEGER NOT NULL | FLOAT

 

 

RETURN 1 IS :: INTEGER | FLOAT

 

╒═══════════════════════╕
│1 IS :: INTEGER | FLOAT│
╞═══════════════════════╡
│true                   │
└───────────────────────┘

 

RETURN 1 IS :: INTEGER NOT NULL | FLOAT NOT NULL

 

╒═════════════════════════════════════════╕
│1 IS :: INTEGER NOT NULL | FLOAT NOT NULL│
╞═════════════════════════════════════════╡
│true                                     │
└─────────────────────────────────────────┘

 

Type predicate expression for properties

Type predicate expressions can also be used to filter out nodes or relationships with properties of a certain type.

MATCH (n:Person)
WHERE n.age IS :: INTEGER AND n.age > 18
RETURN n.name AS name, n.age AS age

The type PROPERTY VALUE can also be used to check whether a type is storable as a property. Types not storable in properties, such as MAP, will return false when checked with IS :: PROPERTY VALUE.

Type predicate expressions for numbers of different sizes

For numerical values passed in as parameters, Cypher does not take the size of the number into account. Cypher will therefore regard any exact numerical parameter as an INTEGER regardless of its declared size. For example, an INT16 or an INT32 passed through from a language library will both be treated by Cypher as an INTEGER. Note that any exact numerical parameter used must fit within the range of an INT64.

Syntactical variations of type predicate expressions

Type predicate expressions allow for some alternative syntax:

<expr> IS TYPED <TYPE>
<expr> :: <TYPE>

For verifying that an expression is not of a certain type, the following alternative syntax is supported:

<expr> IS NOT TYPED <TYPE>

Use of ANY and NOTHING types

ANY is a supertype which matches values of all types. NOTHING is a type containing an empty set of values. This means that it returns false for all values.

RETURN 42 IS :: ANY AS isOfTypeAny, 42 IS :: NOTHING AS isOfTypeNothing

 

╒═══════════╤═══════════════╕
│isOfTypeAny│isOfTypeNothing│
╞═══════════╪═══════════════╡
│true       │false          │
└───────────┴───────────────┘

Closed Dynamic Unions

Closed dynamic union types allow for the testing of multiple types in the same predicate.

UNWIND [42, 42.0, "42"] as val
RETURN val, val IS :: INTEGER | FLOAT AS isNumber

 

╒════╤════════╕
│val │isNumber│
╞════╪════════╡
│42  │true    │
├────┼────────┤
│42.0│true    │
├────┼────────┤
│"42"│false   │
└────┴────────┘

List Types

Type predicate expressions can be used for LIST types, where the inner type of the elements in the list must be specified. If the inner type is not relevant, then the ANY type may be used.

For a LIST type check to return true, all values in the list must match the inner type.

UNWIND [[42], [42, null], [42, 42.0]] as val
RETURN val, val IS :: LIST<INTEGER> AS isIntList

 

╒══════════╤═════════╕
│val       │isIntList│
╞══════════╪═════════╡
│[42]      │true     │
├──────────┼─────────┤
│[42, null]│true     │
├──────────┼─────────┤
│[42, 42.0]│false    │
└──────────┴─────────┘

An empty list will match on all inner types, even the NOTHING type.

RETURN
    [] IS :: LIST<NOTHING> AS isNothingList,
    [] IS :: LIST<INTEGER> AS isIntList,
    [] IS :: LIST<FLOAT NOT NULL> AS isFloatNotNullList

 

╒═════════════╤═════════╤══════════════════╕
│isNothingList│isIntList│isFloatNotNullList│
╞═════════════╪═════════╪══════════════════╡
│true         │true     │true              │
└─────────────┴─────────┴──────────────────┘

Lists can be combined with closed dynamic union types to create tests for heterogeneous lists.

WITH [1, 0, true, false] AS booleanList
RETURN booleanList IS :: LIST<BOOLEAN | INTEGER> as isMixedList

 

╒═══════════╕
│isMixedList│
╞═══════════╡
│true       │
└───────────┘

 

posted on 2025-03-07 16:26  ZhangZhihuiAAA  阅读(47)  评论(0)    收藏  举报