0
# Graph Data Types
1
2
Neo4j graph data types including nodes, relationships, and paths with comprehensive type checking utilities.
3
4
## Capabilities
5
6
### Node Type
7
8
Represents a node in the Neo4j graph with identity, labels, and properties.
9
10
```typescript { .api }
11
interface Node {
12
/** Unique node identity within the database */
13
identity: Integer;
14
15
/** Array of labels assigned to the node */
16
labels: string[];
17
18
/** Key-value properties stored on the node */
19
properties: Record<string, any>;
20
21
/** Convert node to string representation */
22
toString(): string;
23
}
24
25
/**
26
* Check if an object is a Neo4j Node
27
* @param obj - Object to check
28
* @returns true if object is a Node instance
29
*/
30
function isNode(obj: any): obj is Node;
31
```
32
33
**Usage Examples:**
34
35
```typescript
36
import { driver, auth, isNode } from "neo4j-driver";
37
38
const session = neo4jDriver.session();
39
40
try {
41
const result = await session.run(`
42
CREATE (p:Person:User {
43
name: $name,
44
age: $age,
45
email: $email,
46
createdAt: datetime()
47
})
48
RETURN p
49
`, {
50
name: "Alice Johnson",
51
age: 30,
52
email: "alice@example.com"
53
});
54
55
const nodeRecord = result.records[0];
56
const person = nodeRecord.get("p");
57
58
if (isNode(person)) {
59
console.log(`Node ID: ${person.identity}`);
60
console.log(`Labels: ${person.labels.join(", ")}`); // "Person, User"
61
console.log(`Name: ${person.properties.name}`); // "Alice Johnson"
62
console.log(`Age: ${person.properties.age}`); // 30
63
console.log(`Email: ${person.properties.email}`); // "alice@example.com"
64
65
// Access all properties
66
Object.entries(person.properties).forEach(([key, value]) => {
67
console.log(`${key}: ${value}`);
68
});
69
}
70
} finally {
71
await session.close();
72
}
73
```
74
75
### Relationship Type
76
77
Represents a relationship between nodes with type, properties, and endpoint references.
78
79
```typescript { .api }
80
interface Relationship {
81
/** Unique relationship identity within the database */
82
identity: Integer;
83
84
/** Identity of the start node */
85
start: Integer;
86
87
/** Identity of the end node */
88
end: Integer;
89
90
/** Relationship type name */
91
type: string;
92
93
/** Key-value properties stored on the relationship */
94
properties: Record<string, any>;
95
96
/** Convert relationship to string representation */
97
toString(): string;
98
}
99
100
/**
101
* Check if an object is a Neo4j Relationship
102
* @param obj - Object to check
103
* @returns true if object is a Relationship instance
104
*/
105
function isRelationship(obj: any): obj is Relationship;
106
```
107
108
**Usage Examples:**
109
110
```typescript
111
const result = await session.run(`
112
MATCH (p1:Person {name: $name1}), (p2:Person {name: $name2})
113
CREATE (p1)-[r:KNOWS {
114
since: date(),
115
strength: $strength,
116
context: $context
117
}]->(p2)
118
RETURN r, p1, p2
119
`, {
120
name1: "Alice",
121
name2: "Bob",
122
strength: 0.8,
123
context: "work"
124
});
125
126
const record = result.records[0];
127
const relationship = record.get("r");
128
const startNode = record.get("p1");
129
const endNode = record.get("p2");
130
131
if (isRelationship(relationship)) {
132
console.log(`Relationship ID: ${relationship.identity}`);
133
console.log(`Type: ${relationship.type}`); // "KNOWS"
134
console.log(`From: ${relationship.start} To: ${relationship.end}`);
135
console.log(`Since: ${relationship.properties.since}`);
136
console.log(`Strength: ${relationship.properties.strength}`); // 0.8
137
console.log(`Context: ${relationship.properties.context}`); // "work"
138
139
// Verify endpoints match nodes
140
console.log(`Start matches: ${relationship.start.equals(startNode.identity)}`);
141
console.log(`End matches: ${relationship.end.equals(endNode.identity)}`);
142
}
143
```
144
145
### Unbound Relationship Type
146
147
Represents relationship data without specific start/end node references.
148
149
```typescript { .api }
150
interface UnboundRelationship {
151
/** Unique relationship identity within the database */
152
identity: Integer;
153
154
/** Relationship type name */
155
type: string;
156
157
/** Key-value properties stored on the relationship */
158
properties: Record<string, any>;
159
160
/** Convert unbound relationship to string representation */
161
toString(): string;
162
}
163
164
/**
165
* Check if an object is a Neo4j UnboundRelationship
166
* @param obj - Object to check
167
* @returns true if object is an UnboundRelationship instance
168
*/
169
function isUnboundRelationship(obj: any): obj is UnboundRelationship;
170
```
171
172
**Usage Examples:**
173
174
```typescript
175
// Unbound relationships typically appear in path segments
176
const result = await session.run(`
177
MATCH path = (start:Person {name: $name})-[*1..3]-(end:Person)
178
RETURN path
179
`, { name: "Alice" });
180
181
result.records.forEach(record => {
182
const path = record.get("path");
183
184
path.segments.forEach(segment => {
185
if (isUnboundRelationship(segment.relationship)) {
186
console.log(`Unbound relationship: ${segment.relationship.type}`);
187
console.log(`Properties:`, segment.relationship.properties);
188
}
189
});
190
});
191
```
192
193
### Path Type
194
195
Represents a path through the graph containing nodes and relationships.
196
197
```typescript { .api }
198
interface Path {
199
/** Starting node of the path */
200
start: Node;
201
202
/** Ending node of the path */
203
end: Node;
204
205
/** Number of relationships in the path */
206
length: number;
207
208
/** Array of path segments (node-relationship pairs) */
209
segments: PathSegment[];
210
211
/** Array of all nodes in the path */
212
nodes: Node[];
213
214
/** Array of all relationships in the path */
215
relationships: Relationship[];
216
217
/** Convert path to string representation */
218
toString(): string;
219
}
220
221
/**
222
* Check if an object is a Neo4j Path
223
* @param obj - Object to check
224
* @returns true if object is a Path instance
225
*/
226
function isPath(obj: any): obj is Path;
227
```
228
229
**Usage Examples:**
230
231
```typescript
232
const result = await session.run(`
233
MATCH path = (start:Person {name: $name})-[:KNOWS*1..3]-(end:Person)
234
WHERE start <> end
235
RETURN path
236
LIMIT 5
237
`, { name: "Alice" });
238
239
result.records.forEach(record => {
240
const path = record.get("path");
241
242
if (isPath(path)) {
243
console.log(`Path from ${path.start.properties.name} to ${path.end.properties.name}`);
244
console.log(`Path length: ${path.length} relationships`);
245
246
// Examine each segment
247
path.segments.forEach((segment, index) => {
248
console.log(`Segment ${index + 1}:`);
249
console.log(` Node: ${segment.start.properties.name}`);
250
console.log(` Relationship: ${segment.relationship.type}`);
251
console.log(` End: ${segment.end.properties.name}`);
252
});
253
254
// Alternative: iterate through nodes and relationships
255
console.log("Path nodes:", path.nodes.map(n => n.properties.name).join(" -> "));
256
console.log("Relationship types:", path.relationships.map(r => r.type).join(", "));
257
}
258
});
259
```
260
261
### Path Segment Type
262
263
Represents a single segment of a path containing a relationship and its connected nodes.
264
265
```typescript { .api }
266
interface PathSegment {
267
/** Starting node of the segment */
268
start: Node;
269
270
/** Relationship in the segment */
271
relationship: Relationship;
272
273
/** Ending node of the segment */
274
end: Node;
275
276
/** Convert path segment to string representation */
277
toString(): string;
278
}
279
280
/**
281
* Check if an object is a Neo4j PathSegment
282
* @param obj - Object to check
283
* @returns true if object is a PathSegment instance
284
*/
285
function isPathSegment(obj: any): obj is PathSegment;
286
```
287
288
**Usage Examples:**
289
290
```typescript
291
const result = await session.run(`
292
MATCH path = (a:Person)-[r:WORKS_FOR]->(c:Company)-[r2:LOCATED_IN]->(city:City)
293
RETURN path
294
LIMIT 1
295
`);
296
297
const path = result.records[0].get("path");
298
299
if (isPath(path)) {
300
path.segments.forEach((segment, index) => {
301
if (isPathSegment(segment)) {
302
console.log(`Segment ${index + 1}:`);
303
console.log(` Start: ${segment.start.labels.join(":")} ${segment.start.properties.name}`);
304
console.log(` Relationship: ${segment.relationship.type}`);
305
console.log(` End: ${segment.end.labels.join(":")} ${segment.end.properties.name}`);
306
307
// Access relationship properties
308
if (Object.keys(segment.relationship.properties).length > 0) {
309
console.log(` Relationship properties:`, segment.relationship.properties);
310
}
311
}
312
});
313
}
314
```
315
316
### Graph Type Utilities
317
318
Utility object containing all graph type checking functions.
319
320
```typescript { .api }
321
declare const graph: {
322
/** Check if object is a Node */
323
isNode: typeof isNode;
324
325
/** Check if object is a Relationship */
326
isRelationship: typeof isRelationship;
327
328
/** Check if object is an UnboundRelationship */
329
isUnboundRelationship: typeof isUnboundRelationship;
330
331
/** Check if object is a Path */
332
isPath: typeof isPath;
333
334
/** Check if object is a PathSegment */
335
isPathSegment: typeof isPathSegment;
336
};
337
```
338
339
**Usage Examples:**
340
341
```typescript
342
import { graph } from "neo4j-driver";
343
344
const result = await session.run(`
345
MATCH path = (p:Person)-[r:KNOWS]->(friend:Person)
346
RETURN p, r, friend, path
347
LIMIT 1
348
`);
349
350
const record = result.records[0];
351
352
// Type checking with utility object
353
if (graph.isNode(record.get("p"))) {
354
console.log("Found a person node");
355
}
356
357
if (graph.isRelationship(record.get("r"))) {
358
console.log("Found a knows relationship");
359
}
360
361
if (graph.isPath(record.get("path"))) {
362
console.log("Found a friendship path");
363
}
364
365
// Generic type checking function
366
function analyzeGraphObject(obj: any, name: string) {
367
if (graph.isNode(obj)) {
368
console.log(`${name} is a Node with labels: ${obj.labels.join(", ")}`);
369
} else if (graph.isRelationship(obj)) {
370
console.log(`${name} is a Relationship of type: ${obj.type}`);
371
} else if (graph.isPath(obj)) {
372
console.log(`${name} is a Path with ${obj.length} relationships`);
373
} else if (graph.isPathSegment(obj)) {
374
console.log(`${name} is a PathSegment`);
375
} else if (graph.isUnboundRelationship(obj)) {
376
console.log(`${name} is an UnboundRelationship of type: ${obj.type}`);
377
} else {
378
console.log(`${name} is not a graph type`);
379
}
380
}
381
382
// Analyze all returned values
383
record.keys.forEach(key => {
384
analyzeGraphObject(record.get(key), key);
385
});
386
```
387
388
### Working with Complex Graph Structures
389
390
**Usage Examples:**
391
392
```typescript
393
// Complex path analysis
394
const result = await session.run(`
395
MATCH path = (person:Person {name: $name})-[:LIVES_IN]->
396
(city:City)-[:LOCATED_IN]->
397
(country:Country)
398
RETURN path, person, city, country
399
`, { name: "Alice" });
400
401
result.records.forEach(record => {
402
const path = record.get("path");
403
404
if (isPath(path)) {
405
// Analyze path structure
406
console.log(`Path: ${path.start.properties.name} lives in ${path.end.properties.name}`);
407
console.log(`Path contains ${path.nodes.length} nodes and ${path.relationships.length} relationships`);
408
409
// Extract specific information
410
const person = path.nodes.find(n => n.labels.includes("Person"));
411
const city = path.nodes.find(n => n.labels.includes("City"));
412
const country = path.nodes.find(n => n.labels.includes("Country"));
413
414
if (person && city && country) {
415
console.log(`${person.properties.name} lives in ${city.properties.name}, ${country.properties.name}`);
416
}
417
418
// Analyze relationships
419
path.relationships.forEach(rel => {
420
if (rel.type === "LIVES_IN") {
421
console.log(`Living since: ${rel.properties.since || "unknown"}`);
422
} else if (rel.type === "LOCATED_IN") {
423
console.log(`City is in country: ${rel.properties.established || "unknown"}`);
424
}
425
});
426
}
427
});
428
```