Star

Created With

linkWhere Parameters

An instance of the Where class can be used to easily create a statement and a bind parameter to be used in a query.

linkType-Safe Where Parameters

When using TypeScript with Models, where parameters are type-checked to ensure both property names AND value types match your model's schema. This catches typos and type mismatches at compile time rather than runtime.

1linkimport { Op } from 'neogma';

2link

3link// Assuming Users is a Model with properties: { id: string, name: string, age: number }

4link

5link// Valid - correct property names and matching value types

6linkawait Users.findMany({

7link where: { name: 'John', age: 25 }

8link});

9link

10link// TypeScript Error - 'nam' is not a valid property

11linkawait Users.findMany({

12link where: { nam: 'John' } // Error: 'nam' does not exist in type

13link});

14link

15link// TypeScript Error - age expects number, not string

16linkawait Users.findMany({

17link where: { age: 'twenty-five' } // Error: string is not assignable to number

18link});

19link

20link// TypeScript Error - operators also validate value types

21linkawait Users.findMany({

22link where: { age: { [Op.gt]: '18' } } // Error: Op.gt expects number, not string

23link});

linkType-Safe Relationship Queries

For findRelationships, relateTo, and similar methods, the type system validates property names for source, target, and relationship separately:

1linkimport { Op } from 'neogma';

2link

3link// Assuming Users is a Model with an 'Orders' relationship

4linkawait Users.findRelationships({

5link alias: 'Orders',

6link where: {

7link source: { name: 'John' }, // User property

8link target: { orderNumber: 'ORD-123' }, // Order property

9link relationship: { rating: 5 }, // Relationship property

10link },

11link});

12link

13link// TypeScript Error - wrong property names

14linkawait Users.findRelationships({

15link alias: 'Orders',

16link where: {

17link source: { userName: 'John' }, // Error: should be 'name'

18link target: { grpName: 'Test' }, // Error: 'grpName' doesn't exist

19link },

20link});

This type safety works with all where operators (Op.eq, Op.in, Op.gt, Op.is, etc.) and validates both property names and value types at any nesting level.

linkNull vs Undefined Behavior

When using where parameters, null and undefined are handled differently:

1link// undefined is ignored - no filter for 'deleted'

2linkawait Users.findMany({

3link where: { name: 'John', deleted: undefined }

4link});

5link// Generates: WHERE n.name = $name

6link

7link// null generates IS NULL check

8linkawait Users.findMany({

9link where: { name: 'John', deleted: null }

10link});

11link// Generates: WHERE n.name = $name AND n.deleted IS NULL

linkCreating a Where instance and getting its values

Creating a Where instance with values for the identifier n

1linkconst where = new Where({

2link /* --> the node identifier is the key */

3link n: {

4link /* --> the per-identifier where values are used */

5link x: 5,

6link y: 'bar'

7link }

8link});

9link

10link/* --> a statement can be generated to be used in the query */

11linkconsole.log(where.getStatement('text')); // "n.x = $x AND n.y = $y"

12link/* --> the "bindParam" property has a BindParam instance whose values can be used in the query */

13linkconsole.log(where.bindParam.get()); // { x: 5, y: 'bar' }

Creating a Where instance with values for the identifiers n and o

1linkconst where = new Where({

2link n: {

3link x: 5,

4link y: 'bar'

5link },

6link o: {

7link z: true,

8link }

9link});

10link

11linkconsole.log(where.getStatement('text')); // "n.x = $x AND n.y = $y AND o.z = $z"

12linkconsole.log(where.bindParam.get()); // { x: 5, y: 'bar', z: true }

Since Where uses a BindParam, non-unique keys can be used which will be automatically associated with a unique key

1linkconst where = new Where({

2link n: {

3link x: 5,

4link y: 'bar'

5link },

6link o: {

7link /* --> since it's for a different identifier, we can use any key we want, even if it's used in another identifier */

8link x: true,

9link }

10link});

11link

12linkconsole.log(where.getStatement('text')); // "n.x = $x AND n.y = $y AND o.x = $x__aaaa"

13linkconsole.log(where.bindParam.get()); // { x: 5, y: 'bar', x_aaaa: true }

An existing BindParam instance can be used, to ensure unique keys. The same instance will be used in the Where instance, so it will be mutated.

1linkconst existingBindParam = new BindParam({

2link x: 4,

3link});

4link

5linkconst where = new Where(

6link {

7link n: {

8link /* --> the same key as in the bind param can be used */

9link x: 5,

10link y: 'bar'

11link }

12link },

13link existingBindParam

14link);

15link

16link/* --> the "x" key already exists in the bind param, so a new one is used */

17linkconsole.log(where.getStatement('text')); // "n.x = $x__aaaa AND n.y = $y"

18linkconsole.log(where.bindParam.get()); // { x: 4, x_aaaa: 5, y: 'bar' }

19linkconsole.log(where.bindParam === existingBindParam); // true

An existing Where instance can be used. In this case, the parameters of it will be merged with the one that's being created. The existing Where instance won't be mutated at all.

1linkconst existingWhere = new Where(

2link {

3link n: {

4link x: 4

5link },

6link o: {

7link z: true

8link }

9link }

10link);

11link

12linkconsole.log(existingWhere.getStatement('text')); // "n.x = $x AND o.z = $z"

13linkconsole.log(existingWhere.bindParam.get()); // { x: 4, z: true }

14link

15linkconst newWhere = new Where(

16link {

17link n: {

18link y: 'bar'

19link },

20link m: {

21link z: 'foo'

22link }

23link },

24link existingWhere

25link);

26link

27linkconsole.log(newWhere.getStatement('text')); // "n.x = $x AND n.y = $y AND o.z = $z AND m.z = $z__aaaa"

28linkconsole.log(newWhere.bindParam.get()); // { x: 4, y: 'bar', z: true, z__aaaa: 'foo' }

linkAdding parameters to an existing Where instance

Similarly to creating a new Where instance, parameters can be added to an existing instance.

1linkconst where = new Where({

2link n: {

3link x: 5,

4link y: 'bar'

5link }

6link});

7link

8linkwhere.addParams({

9link n: {

10link z: true

11link },

12link o: {

13link x: 4

14link }

15link});

16link

17linkconsole.log(where.getStatement('text')); // "n.x = $x AND n.y = $y AND n.z = $z AND o.x = $x__aaaa"

18linkconsole.log(where.bindParam.get()); // { x: 5, y: 'bar', z: true, x__aaaa: 4 }

linkGetting the statement of a Where instance

A Where instance can easily be used in a query using its statement and bindParam properties

linkText form

This is how the statement can be used in a "text" form

1linkconst where = new Where({

2link n: {

3link x: 5,

4link y: 'bar'

5link },

6link o: {

7link z: true,

8link }

9link});

10link

11linkconst textStatement = where.getStatement('text'); // n.x = $x AND n.y = $y AND o.z = $z

12linkconst bindParamProperties = where.bindParam.get(); // { x: 5, y: 'bar', z: true }

13link

14linkawait queryRunner.run(

15link `MATCH (n), (o) WHERE ${textStatement} RETURN n, o`,

16link bindParamProperties

17link);

linkObject form

This is how the statement can be used in an "object" form

1linkconst where = new Where({

2link n: {

3link x: 5,

4link y: 'bar'

5link },

6link});

7link

8linkconst objectStatement = where.getStatement('object'); // { x: $x, y: $y }

9linkconst bindParamProperties = where.bindParam.get(); // { x: 5, y: 'bar' }

10link

11linkawait queryRunner.run(

12link `MATCH (n ${objectStatement}) RETURN n`,

13link bindParamProperties

14link);

This ignores the identifier, and is only available for the "equals" operator. So, it's recommended that it's used with only 1 identifier.

linkWhere operators

While some of the operators can be used with plain objects, some others need to use the exported Op variable. It contains symbols for the operators.

linkOperator Reference

OperatorCypherDescriptionAvailable For
Op.eq= / IS NULLEquality (null → IS NULL)All types
Op.ne<> / IS NOT NULLNot equal (null → IS NOT NULL)All types
Op.inproperty IN [values]Property is one of valuesAll types
Op._invalue IN propertyValue exists in array propertyAll types (use for array membership)
Op.gt>Greater thanScalar types only
Op.gte>=Greater than or equalScalar types only
Op.lt<Less thanScalar types only
Op.lte<=Less than or equalScalar types only
Op.containsCONTAINSSubstring matchingString only
Op.isIS NULLProperty is nullAll types
Op.isNotIS NOT NULLProperty is not nullAll types
nullIS NULLShorthand for { [Op.is]: null }All types

Type Safety Note: When using TypeScript with typed models, operators are constrained to appropriate types. For example, Op.contains only accepts string values and is only valid for string properties.

linkEquals

A direct object value corresponds to equality.

1linkconst where = new Where({

2link n: {

3link x: 5

4link },

5link});

6link

7linkconsole.log(where.getStatement('text')); // n.x = $x

8linkconsole.log(where.getStatement('object')); // { x: $x }

9linkconsole.log(where.bindParam.get()); // { x: 5 }

Alternatively, the operator "eq" can be used.

1linkconst where = new Where({

2link n: {

3link x: {

4link [Op.eq]: 5,

5link }

6link },

7link});

8link

9linkconsole.log(where.getStatement('text')); // n.x = $x

10linkconsole.log(where.getStatement('object')); // { x: $x }

11linkconsole.log(where.bindParam.get()); // { x: 5 }

linkAnd

The values of the parameters object are separated by an "and" operator

1linkconst where = new Where({

2link n: {

3link x: 5,

4link y: 'bar'

5link },

6link});

7link

8linkconsole.log(where.getStatement('text')); // n.x = $x AND n.y = $y

9linkconsole.log(where.getStatement('object')); // { x: $x, y: $y }

10linkconsole.log(where.bindParam.get()); // { x: 5, y: 'bar' }

linkIn (Property IN List)

The Op.in operator checks if a property value is one of several values. This generates Cypher's IN clause.

1linkconst where = new Where({

2link n: {

3link x: {

4link [Op.in]: [1, 2, 3],

5link },

6link y: 2

7link },

8link o: {

9link z: {

10link [Op.in]: [4, 5, 6],

11link }

12link }

13link});

14link

15linkconsole.log(where.getStatement('text')); // n.x IN $x AND n.y = $y AND o.z IN $z

16link// "object" statement not available

17linkconsole.log(where.bindParam.get()); // { x: [1, 2, 3], y: 2, z: [4, 5, 6] }

Important - Direct Arrays vs Op.in: A direct array value like { id: ['1', '2'] } is treated as equality at runtime (id = ['1', '2']), NOT as an IN query. Always use { [Op.in]: ['1', '2'] } explicitly when you want IN behavior.

link_In (Element IN Array Property)

The Op._in operator checks if a given value exists within an array property. This is the correct way to check array membership in Cypher (not Op.contains, which is for string substring matching).

1link// Check if 'admin' is in the user's roles array

2linkconst where = new Where({

3link n: {

4link roles: {

5link [Op._in]: 'admin',

6link },

7link },

8link});

9link

10linkconsole.log(where.getStatement('text')); // $roles IN n.roles

11linkconsole.log(where.bindParam.get()); // { roles: 'admin' }

This generates $value IN property which checks if the element exists in the array:

1linkconst where = new Where({

2link n: {

3link x: {

4link [Op._in]: 1,

5link },

6link y: 2

7link },

8link o: {

9link z: {

10link [Op._in]: 2,

11link }

12link }

13link});

14link

15linkconsole.log(where.getStatement('text')); // $x IN n.x AND n.y = $y AND $z IN o.z

16link// "object" statement not available

17linkconsole.log(where.bindParam.get()); // { x: 1, y: 2, z: 2 }

linkWorking with Array-Typed Properties

When querying array-typed properties (like string[] or number[]), a limited set of operators is available:

1link// Assuming Users has: { tags: string[], scores: number[] }

2link

3link// Check if an element exists in the array (use Op._in)

4linkawait Users.findMany({

5link where: { tags: { [Op._in]: 'admin' } } // generates: $tags IN u.tags

6link});

7link

8link// Exact array match

9linkawait Users.findMany({

10link where: { tags: { [Op.eq]: ['admin', 'user'] } }

11link});

12link

13link// Array not equal

14linkawait Users.findMany({

15link where: { tags: { [Op.ne]: ['guest'] } }

16link});

17link

18link// TypeScript Error - Op.contains is for string substring matching, not array membership

19linkawait Users.findMany({

20link where: { tags: { [Op.contains]: 'admin' } } // Error!

21link});

22link

23link// TypeScript Error - comparison operators don't apply to arrays

24linkawait Users.findMany({

25link where: { scores: { [Op.gt]: [50] } } // Error!

26link});

Key Point: To check if an element exists in an array property, use Op._in (which generates value IN arrayProperty), NOT Op.contains (which is for string substring matching).

linkComparison

The following operators are available:

OperatorDescriptionResults in
nenot equals<>
gtgreater than>
gtegreater than or equals>=
ltless than<
lteless than or equals<=

linkContains (String Substring Matching)

The Op.contains operator performs substring matching on strings only. It generates Cypher's CONTAINS clause, which checks if a string property contains a given substring.

Important: Op.contains is NOT for checking array membership. To check if an element exists in an array property, use Op._in instead (see below).

1linkconst where = new Where({

2link n: {

3link // Finds nodes where n.name contains 'xyz'

4link name: {

5link [Op.contains]: 'xyz',

6link },

7link },

8link});

9link

10linkconsole.log(where.getStatement('text')); // n.name CONTAINS $name

11link// "object" statement not available

12linkconsole.log(where.bindParam.get()); // { name: 'xyz' }

When using TypeScript, Op.contains is only available for string-typed properties:

1link// Valid - string property

2linkawait Users.findMany({ where: { name: { [Op.contains]: 'John' } } });

3link

4link// TypeScript Error - number property

5linkawait Users.findMany({ where: { age: { [Op.contains]: 5 } } }); // Error!

linkIS NULL and IS NOT NULL

Check if a property is null or not null using Op.is and Op.isNot:

1linkconst where = new Where({

2link n: {

3link deleted: { [Op.is]: null },

4link createdAt: { [Op.isNot]: null },

5link },

6link});

7link

8linkconsole.log(where.getStatement('text'));

9link// n.deleted IS NULL AND n.createdAt IS NOT NULL

For convenience, you can use null directly as shorthand for { [Op.is]: null }:

1linkconst where = new Where({

2link n: {

3link deleted: null, // Equivalent to { [Op.is]: null }

4link },

5link});

You can also use { [Op.eq]: null } for IS NULL and { [Op.ne]: null } for IS NOT NULL:

1linkconst where = new Where({

2link n: {

3link deleted: { [Op.eq]: null }, // Generates: n.deleted IS NULL

4link active: { [Op.ne]: null }, // Generates: n.active IS NOT NULL

5link },

6link});

Note: These operators are only available in "text" mode (WHERE clause), not "object" mode (bracket syntax).

linkUsing Operators in QueryBuilder Match

When using operators in QueryBuilder's match() method for nodes or relationships, all operators are supported. The QueryBuilder automatically separates equality operators (which can use Neo4j's bracket syntax { prop: $val }) from non-equality operators (which require a WHERE clause).

linkExample: Using Comparison Operators in Match

1linkconst queryBuilder = new QueryBuilder().match({

2link identifier: 'u',

3link label: 'User',

4link where: {

5link name: 'John', // eq operator - uses bracket syntax

6link age: { [Op.gte]: 18 }, // non-eq - generates WHERE clause

7link },

8link});

9link

10link// Generates: MATCH (u:User { name: $name }) WHERE u.age >= $age

11linkconsole.log(queryBuilder.getStatement());

12link// { name: 'John', age: 18 }

13linkconsole.log(queryBuilder.getBindParam().get());

linkExample: Multiple Operators on Same Property

1linkconst queryBuilder = new QueryBuilder().match({

2link identifier: 'u',

3link label: 'User',

4link where: {

5link age: { [Op.gte]: 18, [Op.lte]: 65 },

6link },

7link});

8link

9link// Generates: MATCH (u:User) WHERE u.age >= $age AND u.age <= $age__aaaa

10linkconsole.log(queryBuilder.getStatement());

linkExample: Operators on Relationships

1linkconst queryBuilder = new QueryBuilder().match({

2link related: [

3link { identifier: 'u', label: 'User' },

4link {

5link direction: 'out',

6link name: 'FOLLOWS',

7link identifier: 'r',

8link where: { since: { [Op.gte]: 2020 } },

9link },

10link { identifier: 'p', label: 'Post' },

11link ],

12link});

13link

14link// Generates: MATCH (u:User)-[r:FOLLOWS]->(p:Post) WHERE r.since >= $since

15linkconsole.log(queryBuilder.getStatement());

linkAuto-generated Identifiers

When using non-equality operators without an explicit identifier, QueryBuilder automatically generates a unique identifier for the WHERE clause:

1link// With explicit identifier

2linknew QueryBuilder().match({

3link identifier: 'n',

4link label: 'Node',

5link where: { age: { [Op.gt]: 18 } },

6link});

7link// Result: MATCH (n:Node) WHERE n.age > $age

8link

9link// Without identifier - one is auto-generated

10linknew QueryBuilder().match({

11link label: 'Node',

12link where: { age: { [Op.gt]: 18 } },

13link});

14link// Result: MATCH (__n:Node) WHERE __n.age > $age

The same applies to relationships - if no identifier is provided and non-equality operators are used, a unique identifier (like __r) is generated automatically.

linkUsing a Custom BindParam

You can pass a custom BindParam instance to the QueryBuilder constructor. The auto-generated identifiers will use this shared BindParam, which is useful for:

1linkimport { BindParam, QueryBuilder, Op } from 'neogma';

2link

3linkconst bindParam = new BindParam();

4link

5linkconst queryBuilder = new QueryBuilder(bindParam).match({

6link label: 'Node',

7link where: { age: { [Op.gt]: 18 } },

8link});

9link

10link// Result: MATCH (__n:Node) WHERE __n.age > $age

11linkconsole.log(queryBuilder.getStatement());

12link

13link// Access bind parameters from either reference

14linkconsole.log(bindParam.get()); // { age: 18 }

15linkconsole.log(queryBuilder.getBindParam().get()); // { age: 18 }

linkUsing a literal string

The class Literal can be used to use any given string in a Where condition.

1linkconst where = new Where({

2link n: {

3link x: 2,

4link y: new Literal('n.x')

5link },

6link o: {

7link z: {

8link [Op.gt]: new Literal('n.y'),

9link }

10link }

11link});

12link

13linkconsole.log(where.getStatement('text')); // n.x = $x AND n.y = n.x AND o.z >= n.y

14link// "object" statement not available

15linkconsole.log(where.bindParam.get()); // { x: 2 }

linkAcquire a Where instance

The acquire static can be used to ensure that a Where instance is at hand. If one is passed, it will be returned as is. If an object with where parameters is passed, a new Where instance will be created with them. Else, a new one will be created.

1linkconst whereFirst = Where.acquire(null);

2linkconsole.log(whereFirst instanceof Where); // true

3link

4linkconst whereSecond = Where.acquire(whereFirst);

5linkconsole.log(whereFirst === whereSecond); // true

6link

7link/* --> an object with where parameters can be used */

8linkconst whereWithPlainParams = Where.acquire({

9link n: {

10link x: 5

11link }

12link});

13linkconsole.log(whereWithPlainParams instanceof Where); // true

14link

15link/* --> a BindParam instance can be passed to be used */

16linkconst existingBindParam = new BindParam({ x: 4 });

17linkconst whereWithBindParams = Where.acquire(

18link {

19link n: {

20link x: 5

21link }

22link },

23link existingBindParam

24link);

25link

26linkconsole.log(whereWithBindParams instanceof Where); // true

27linkconsole.log(whereWithBindParams.statement); // "n.x = $x__aaaa"

28linkconsole.log(whereWithBindParams.bindParam.get()); // { x: 4, x__aaaa: 5 }

Where ParametersType-Safe Where ParametersType-Safe Relationship QueriesNull vs Undefined BehaviorCreating a Where instance and getting its valuesAdding parameters to an existing Where instanceGetting the statement of a Where instanceText formObject formWhere operatorsOperator ReferenceEqualsAndIn (Property IN List)_In (Element IN Array Property)Working with Array-Typed PropertiesComparisonContains (String Substring Matching)IS NULL and IS NOT NULLUsing Operators in QueryBuilder MatchExample: Using Comparison Operators in MatchExample: Multiple Operators on Same PropertyExample: Operators on RelationshipsAuto-generated IdentifiersUsing a Custom BindParamUsing a literal stringAcquire a Where instance

Introduction Getting Started

Modelschevron_right

Sessions and Transactions

Query Builderchevron_right
Query Runnerchevron_right

Bind Parameters

Where Parameters