1 - all() (graph function)

Learn how to use the all() function to evaluate a condition over the elements of a variable length edge.

The all() graph function evaluates a condition for each edge or inner node along a variable length path.

Syntax

all(edge, condition)

all(inner_nodes(edge), condition)

Parameters

NameTypeRequiredDescription
edgestring✔️A variable length edge from the graph-match operator or graph-shortest-paths operator pattern. For more information, see Graph pattern notation.
conditionstring✔️A Boolean expression composed of properties of the edge or inner node, when inner_nodes is used, in the variable length edge. A property is referenced using the property name directly. The expression is evaluated for each edge or inner node in the variable length edge.

Returns

Returns true if the condition evaluates to true for each edge or inner node, when inner_nodes is used, in the variable length edge. Otherwise, it returns false.

For zero length paths, the condition evaluates to true.

Examples

The following example shows how to use the graph-match operator with the all() function to find all round-trip paths between two stations in a transportation network. It uses a different line for each direction. The query constructs a graph from the connections data, finding all paths up to five connections long that use the "red" line for the outward route, and the "blue" line for the return route. The all() function ensures that all edges in the variable length edge are part of the same line, either "red" or "blue".

let connections = datatable(from_station:string, to_station:string, line:string) 
[ 
  "Central", "North", "red",
  "North", "Central", "red", 
  "Central", "South",  "red", 
  "South", "Central",  "red", 
  "South", "South-West", "red", 
  "South-West", "South", "red", 
  "South-West", "West", "red", 
  "West", "South-West", "red", 
  "Central", "East", "blue", 
  "East", "Central", "blue", 
  "Central", "West", "blue",
  "West", "Central", "blue",
]; 
connections 
| make-graph from_station --> to_station with_node_id=station
| graph-match (start)-[outward*1..5]->(destination)-[return*1..5]->(start)
  where start.station != destination.station and 
        all(outward, line == "red") and
        all(return, line == "blue") 
  project from = start.station, 
          outward_stations = strcat_array(map(inner_nodes(outward), station), "->"), 
          to = destination.station, 
          return_stations = strcat_array(map(inner_nodes(return), station), "->"), 
          back=start.station

Output

fromoutward_stationstoreturn_stationsback
CentralNorth->Central->South->South-WestWestCentral
WestSouth-West->South->Central->NorthCentralWest
CentralSouth->South-WestWestCentral
WestSouth-West->SouthCentralWest
CentralNorth->Central->South->South-WestWestCentral->EastCentral
WestSouth-West->South->Central->NorthCentralEast->CentralWest
CentralSouth->South-WestWestCentral->EastCentral
WestSouth-West->SouthCentralEast->CentralWest

The following example shows how to use the graph-shortest-paths operator with the all() and inner_nodes functions to find a path between two stations in a transportation network. The query constructs a graph from the connections data and finds the shortest path from the "South-West" station to the "North" station, passing through stations where Wi-Fi is available.

let connections = datatable(from_station:string, to_station:string, line:string) 
[ 
  "Central", "North", "red",
  "North", "Central", "red", 
  "Central", "South",  "red", 
  "South", "Central",  "red", 
  "South", "South-West", "red", 
  "South-West", "South", "red", 
  "South-West", "West", "red", 
  "West", "South-West", "red", 
  "Central", "East", "blue", 
  "East", "Central", "blue", 
  "Central", "West", "blue",
  "West", "Central", "blue",
]; 
let stations = datatable(station:string, wifi: bool) 
[ 
  "Central", true,
  "North", false,
  "South", false,
  "South-West", true,
  "West", true,
  "East", false
];
connections 
| make-graph from_station --> to_station with stations on station
| graph-shortest-paths (start)-[connections*2..5]->(destination)
  where start.station == "South-West" and
        destination.station == "North" and 
        all(inner_nodes(connections), wifi)
  project from = start.station, 
          stations = strcat_array(map(inner_nodes(connections), station), "->"), 
          to = destination.station

Output

fromstationsto
South-WestWest->CentralNorth

2 - any() (graph function)

Learn how to use the any() function to evaluate a condition over the elements of a variable length edge.

The any() graph function evaluates a condition for each edge or inner node along a variable length path.

Syntax

any(edge, condition)

any(inner_nodes(edge), condition)

Parameters

NameTypeRequiredDescription
edgestring✔️A variable length edge from the graph-match operator or graph-shortest-paths operator pattern. For more information, see Graph pattern notation.
conditionstring✔️A Boolean expression composed of properties of the edge or inner node, when inner_nodes is used, in the variable length edge. A property is referenced using the property name directly. The expression is evaluated for each edge or inner node in the variable length edge.

Returns

Returns true if the condition evaluates to true for at least one edge or inner node, when inner_nodes is used, in the variable length edge. Otherwise, it returns false.

For zero length paths, the condition evaluates to false.

Examples

The following example uses the Locations and Routes data tables to construct a graph that finds paths from a source location to a destination location through a route. It uses any() function to find paths that uses "Train" transportation method at least once. It returns the source location name, destination location name and transportation methods along the route.

// Locations table (nodes)
let Locations = datatable(LocationName: string, LocationType: string) [
    "New York", "City",
    "San Francisco", "City",
    "Chicago", "City",
    "Los Angeles", "City",
    "Seattle", "Warehouse"
];
// Routes table (edges)
let Routes = datatable(OriginLocationID: string, DestinationLocationID: string, TransportMode: string) [
    "New York", "San Francisco", "Truck",
    "New York", "Chicago", "Train",
    "San Francisco", "Los Angeles", "Truck",
    "Chicago", "Seattle", "Train",
    "Los Angeles", "New York", "Truck",
    "Seattle", "San Francisco", "Train"
];
Routes
| make-graph OriginLocationID --> DestinationLocationID with Locations on LocationName
| graph-match (src)-[route*1..2]->(dest)
  where any(route, TransportMode == "Train")
  project src.LocationName, 
        dest.LocationName, 
        route_TransportModes = map(route, TransportMode)

Output

src_LocationNamedest_LocationNameroute_TransportModes
SeattleSan Francisco[“Train”]
ChicagoSeattle[“Train”]
New YorkChicago[“Train”]
SeattleLos Angeles[
“Train”,
“Truck”
]
ChicagoSan Francisco[
“Train”,
“Train”
]
New YorkSeattle[
“Train”,
“Train”
]
Los AngelesChicago[
“Truck”,
“Train”
]

The following example shows how to use the graph-shortest-paths operator with the any() and inner_nodes functions to find a path between two stations in a transportation network. The query constructs a graph from the connections data and finds the shortest path from the "South-West" station to the "North" station, passing through at least one station where Wi-Fi is available.

let connections = datatable(from_station:string, to_station:string, line:string) 
[ 
  "Central", "North", "red",
  "North", "Central", "red", 
  "Central", "South",  "red", 
  "South", "Central",  "red", 
  "South", "South-West", "red", 
  "South-West", "South", "red", 
  "South-West", "West", "red", 
  "West", "South-West", "red", 
  "Central", "East", "blue", 
  "East", "Central", "blue", 
  "Central", "West", "blue",
  "West", "Central", "blue",
]; 
let stations = datatable(station:string, wifi: bool) 
[ 
  "Central", true,
  "North", false,
  "South", false,
  "South-West", true,
  "West", true,
  "East", false
];
connections 
| make-graph from_station --> to_station with stations on station
| graph-match cycles=none  (start)-[connections*2..5]->(destination)
  where start.station == "South-West" and
        destination.station == "North" and 
        any(inner_nodes(connections), wifi)
  project from = start.station, 
          stations = strcat_array(map(inner_nodes(connections), station), "->"), 
          to = destination.station

Output

fromstationsto
South-WestSouth->CentralNorth
South-WestWest->CentralNorth

3 - inner_nodes() (graph function)

Learn how to use the inner_nodes() function to access all inner nodes in a variable length path.

The inner_nodes() graph function allows access to the inner nodes of a variable length edge. It can only be used as the first parameter of the all(), any(), and map() graph functions.

Syntax

inner_nodes(edge)

Parameters

NameTypeRequiredDescription
edgestring✔️A variable length edge from the graph-match operator or graph-shortest-paths operator pattern. For more information, see Graph pattern notation.

Returns

Sets the execution scope of the all, any or map expression to the inner node of a variable length edge.

Examples

The example in this section shows how to use the syntax to help you get started.

Find all employees in a manager’s organization

The following example represents an organizational hierarchy. It shows how a variable length edge in a single graph query can be used to find employees at various levels within an organizational hierarchy. The nodes in the graph represent employees and the edges connect an employee to their manager. After the graph is built using the make-graph operator, the all() and inner_nodes functions are used to search for employees in Alice’s organization besides Alice, who have managers younger than 40. Then, map() and inner_nodes are used together to get those managers’ names.

let employees = datatable(name:string, age:long) 
[ 
  "Alice", 32,  
  "Bob", 31,  
  "Eve", 27,  
  "Joe", 29,  
  "Chris", 45, 
  "Alex", 35,
  "Ben", 23,
  "Richard", 39,
]; 
let reports = datatable(employee:string, manager:string) 
[ 
  "Bob", "Alice",  
  "Chris", "Alice",  
  "Eve", "Bob",
  "Ben", "Chris",
  "Joe", "Alice", 
  "Richard", "Bob"
]; 
reports 
| make-graph employee --> manager with employees on name 
| graph-match (manager)<-[reports*1..5]-(employee)
  where manager.name == "Alice" and all(inner_nodes(reports), age < 40)
  project employee = employee.name, manager = manager.name, reportingPath = map(inner_nodes(reports), name)

Output

employeemanagerreportingPath
BobAlice[]
ChrisAlice[]
JoeAlice[]
EveAlice[“Bob”]
RichardAlice[“Bob”]

4 - labels() (graph function)

Learn how to use the labels() function to retrieve, filter, and project label information for nodes and edges in graph queries.

Retrieves the labels associated with nodes or edges in a graph query. Use this function to filter graph elements by their labels or to include label information in query results.

Labels are defined in graph models and can be either static (fixed labels assigned to node or edge types) or dynamic (labels derived from data properties during graph construction).

Syntax

labels( element )

labels()

Parameters

NameTypeRequiredDescription
elementstring✔️A node or edge variable reference from a graph pattern. Omit this parameter when using labels() inside all(), any(), or map() graph functions with inner_nodes(). For more information, see Graph pattern notation.

Returns

Returns a dynamic array of strings containing the labels associated with the specified node or edge. Returns an empty array for elements without labels or when used with graphs created created with the make-graph operator.

When called without parameters inside all(), any(), or map() with inner_nodes(), returns the labels for each inner node or edge in the path.

Label types

The labels() function retrieves both static and dynamic labels defined in the graph model. For detailed information about static and dynamic labels, including when to use each type, see Labels in Graph models.

Examples

These examples use the sample graphs available on the help cluster in the Samples database. For more information about these datasets, see Graph sample datasets.

Example 1: Filter nodes by labels

This example demonstrates filtering nodes based on their labels using the Simple educational graph. The query finds all people who work at a specific company and filters by the “Person” label.

graph("Simple")
| graph-match (person)-[works_at]->(company)
    where labels(person) has "Person" 
          and company.name == "TechCorp"
    project employee_name = person.name, 
            employee_age = person.properties.age,
            employee_labels = labels(person)
employee_nameemployee_ageemployee_labels
Alice25[“Person”]
Bob30[“Person”]
Emma26[“Person”]

This query uses labels(person) has "Person" to filter only nodes with the “Person” label, ensuring we’re working with person entities rather than other node types in the graph.

Example 2: Project labels in results

This example shows how to include label information in query results when analyzing social network connections using the LDBC SNB Interactive dataset. The query finds people who like posts and projects their labels.

graph("LDBC_SNB_Interactive")
| graph-match (person)-[likes]->(post)-[has_creator]->(creator)
    where labels(person) has "PERSON" 
          and labels(post) has "POST"
          and labels(has_creator) has "HAS_CREATOR"
    project 
        person_name = person.firstName,
        creator_name = creator.firstName,
        person_labels = labels(person),
        post_labels = labels(post),
        edge_labels = labels(has_creator)
| take 5
person_namecreator_nameperson_labelspost_labelsedge_labels
AbdullahMahinda[“PERSON”][“POST”][“HAS_CREATOR”]
AbdullahMahinda[“PERSON”][“POST”][“HAS_CREATOR”]
AbdullahMahinda[“PERSON”][“POST”][“HAS_CREATOR”]
AbdullahMahinda[“PERSON”][“POST”][“HAS_CREATOR”]
KarlMahinda[“PERSON”][“POST”][“HAS_CREATOR”]

This query projects the labels using labels() for both nodes and edges, showing how labels help categorize different entity types in a complex social network.

Example 3: Filter by multiple label conditions

This example demonstrates using multiple label conditions to identify financial transaction patterns in the LDBC Financial dataset. The query finds accounts that transfer money to other accounts and filters by specific node and edge labels.

graph("LDBC_Financial")
| graph-match (account1)-[transfer]->(account2)
    where labels(account1) has "ACCOUNT" 
          and labels(account2) has "ACCOUNT"
          and labels(transfer) has "TRANSFER"
          and transfer.amount > 1000000
    project 
        from_account = account1.node_id,
        to_account = account2.node_id,
        amount = transfer.amount,
        source_labels = labels(account1),
        target_labels = labels(account2),
        edge_labels = labels(transfer)
| take 5
from_accountto_accountamountsource_labelstarget_labelsedge_labels
Account::56576470318842045Account::46527813650271453965602050,75[“ACCOUNT”][“ACCOUNT”][“TRANSFER”]
Account::56576470318842045Account::46747364132105765847542124,31[“ACCOUNT”][“ACCOUNT”][“TRANSFER”]
Account::4695847036463875613Account::419397715298881002798953,34[“ACCOUNT”][“ACCOUNT”][“TRANSFER”]
Account::40532396646334920Account::990791918021513981893602,99[“ACCOUNT”][“ACCOUNT”][“TRANSFER”]
Account::98797716825440579Account::46755808381407076113952004,86[“ACCOUNT”][“ACCOUNT”][“TRANSFER”]

This query chains multiple label conditions to ensure both nodes and edges have the correct types, which is essential for accurate pattern matching in financial networks.

Example 4: Use labels() with inner_nodes() and collection functions

This example demonstrates using labels() without parameters inside any() and map() functions combined with inner_nodes() when working with variable-length paths in the BloodHound Active Directory dataset. The query finds privilege escalation paths where at least one edge along the path has dangerous permission labels, and also filters based on the labels of intermediate nodes.

graph("BloodHound_AD")
| graph-match (user)-[path*1..3]->(target)
    where labels(user) has "User" 
          and labels(target) has "Group"
          and target.properties.admincount == true
          and any(path, labels() has_any ("GenericAll", "WriteDacl", "WriteOwner", "GenericWrite", "Owns"))
          and all(inner_nodes(path), labels() has_any ("User", "Group"))
    project 
        attacker = user.name,
        target_group = target.name,
        path_length = array_length(path),
        permission_chain = map(path, labels()),
        intermediate_node_labels = map(inner_nodes(path), labels())
| take 5
attackertarget_grouppath_lengthpermission_chainintermediate_node_labels
HACKERDA@PHANTOM.CORPADMINISTRATORS@PHANTOM.CORP2[[“MemberOf”], [“WriteOwner”]][[“Base”, “Group”]]
ROSHI@PHANTOM.CORPADMINISTRATORS@PHANTOM.CORP2[[“MemberOf”], [“WriteOwner”]][[“Base”, “Group”]]
FABIAN@PHANTOM.CORPADMINISTRATORS@PHANTOM.CORP2[[“MemberOf”], [“WriteOwner”]][[“Base”, “Group”]]
ANDY@PHANTOM.CORPADMINISTRATORS@PHANTOM.CORP2[[“MemberOf”], [“WriteOwner”]][[“Base”, “Group”]]
CHARLIE@PHANTOM.CORPADMINISTRATORS@PHANTOM.CORP2[[“MemberOf”], [“WriteOwner”]][[“Base”, “Group”]]

In this query, labels() is used in multiple ways:

  • With any(path, labels() has_any (...)) to check edge labels for dangerous permissions
  • With all(inner_nodes(path), labels() has_any (...)) to filter paths based on intermediate node labels
  • With map(path, labels()) to show the edge labels along each path
  • With map(inner_nodes(path), labels()) to display the labels of intermediate nodes in the path

This demonstrates how labels() works seamlessly with inner_nodes() to access both edge and node labels in variable-length paths.

5 - map() (graph function)

Learn how to use the map() function to evaluate an expression over the elements of a variable length edge.

The map() graph function calculates an expression for each edge or inner node along a variable length path and returns a dynamic array of all results.

Syntax

map(*edge*, *expression*)`

map(inner_nodes(edge), expression)

Parameters

NameTypeRequiredDescription
edgestring✔️A variable length edge from the graph-match operator or graph-shortest-paths operator pattern. For more information, see Graph pattern notation.
expressionstring✔️The calculation to perform over the properties of the edge or inner node, when inner_nodes is used, in the variable length edge. A property is referenced using the property name directly. The expression is evaluated for each edge or inner node in the variable length edge.

Returns

A dynamic array where:

  • The array length matches the number of edges or inner nodes, when inner_nodes is used, in the variable length edge.
  • The array is empty for zero length paths.
  • Each element in the array corresponds to the results of applying the expression to each edge or inner node in the variable length edge.

Examples

The examples in this section show how to use the syntax to help you get started.

Find the station and line for the shortest route between two stations

The following example shows how to use the graph-shortest-paths operator to find the shortest path between the "South-West" and "North" stations in a transportation network. It adds line information to the path using the map() function. The query constructs a graph from the connections data, considering paths up to five connections long.

let connections = datatable(from_station:string, to_station:string, line:string) 
[ 
  "Central", "North", "red",
  "North", "Central", "red", 
  "Central", "South",  "red", 
  "South", "Central",  "red", 
  "South", "South-West", "red", 
  "South-West", "South", "red", 
  "South-West", "West", "red", 
  "West", "South-West", "red", 
  "Central", "East", "blue", 
  "East", "Central", "blue", 
  "Central", "West", "blue",
  "West", "Central", "blue",
]; 
connections 
| make-graph from_station --> to_station with_node_id=station
| graph-shortest-paths (start)-[connections*1..5]->(destination)
  where start.station == "South-West" and destination.station == "North"
  project from = start.station, path = map(connections, strcat(to_station, " (", line, ")")), to = destination.station

Output

frompathto
South-West[
“South (red)”,
“Central (red)”,
“North (red)"
]
North

Get list of stopovers with Wi-Fi in all routes between two stations

The following example shows how to use the graph-match operator with the all() and inner_nodes functions to find all stopovers with Wi-Fi along all routes between two stations in a transportation network.

let connections = datatable(from_station:string, to_station:string, line:string) 
[ 
  "Central", "North", "red",
  "North", "Central", "red", 
  "Central", "South",  "red", 
  "South", "Central",  "red", 
  "South", "South-West", "red", 
  "South-West", "South", "red", 
  "South-West", "West", "red", 
  "West", "South-West", "red", 
  "Central", "East", "blue", 
  "East", "Central", "blue", 
  "Central", "West", "blue",
  "West", "Central", "blue",
]; 
let stations = datatable(station:string, wifi:bool) 
[ 
  "Central", true,
  "North", false,
  "South", false,
  "South-West", true,
  "West", true,
  "East", false
];
connections 
| make-graph from_station --> to_station with stations on station
| graph-match cycles=none (start)-[connections*1..5]->(destination)
  where start.station == "South-West" and destination.station == "East"
  project stopovers = strcat_array(map(inner_nodes(connections), station), "->"),
          stopovers_with_wifi = set_intersect(map(inner_nodes(connections), station), map(inner_nodes(connections), iff(wifi, station, "")))

Output

stopoversstopovers_with_wifi
West->Central[ “West”, “Central”]
South->Central[ “Central”]

6 - node_degree_in (graph function)

This article describes the node_degree_in() command.

The node_degree_in function calculates the in-degree, or number of incoming edges, to a node in a directed graph.

Syntax

node_degree_in([node])

Parameters

NameTypeRequiredDescription
nodestringThe reference to a graph node variable in a graph pattern.
Don’t pass any parameters when used inside all(), any(), and map() graph functions, with inner_nodes().

Returns

Returns the in-degree of the input node or of all inner nodes, when used inside all(), any(), and map() functions with inner_nodes().

Example

The following example creates a graph to analyze a hierarchical structure of employees and their managers.

The graph-match operator looks for managers who have exactly three direct reports (node_degree_in(manager) == 3) and where any of the inner nodes (employees) have at least one report (node_degree_in() > 1).

The query returns the manager, the name of each direct report, the in-degree to the manager, and the number of direct reports for each employee.

let employees = datatable(name:string, age:long)
[
"Alice", 32,
"Bob", 31,
"Eve", 27,
"Joe", 29,
"Chris", 45,
"Alex", 35,
"Ben", 23,
"Richard", 39,
];
let reports = datatable(employee:string, manager:string)
[
"Bob", "Alice",
"Chris", "Alice",
"Eve", "Bob",
"Ben", "Chris",
"Joe", "Alice",
"Richard", "Bob"
];
reports
| make-graph employee --> manager with employees on name
| graph-match (manager)<-[reports*1..3]-(employee)
    where node_degree_in(manager) == 3 and any(inner_nodes(reports), node_degree_in() > 1)
    project manager.name, employee.name, 
            reports_and_inner_nodes_degree_in = map(inner_nodes(reports), strcat(name, " has ", node_degree_in(), " reports")),
            degree_in_m=node_degree_in(manager), 
            degree_out_e=node_degree_out(employee) 

Output

manager_nameemployee_namereports_and_inner_nodes_degree_indegree_in_mdegree_out_e
AliceRichard[“Bob has 2 reports”]31
AliceEve[“Bob has 2 reports”]31
AliceEllen[
“Bob has 2 reports”,
“Eve has 1 reports”
]
31

7 - node_degree_out (graph function)

This article describes the node_degree_out() command.

The node_degree_out function calculates the out-degree, or number of outgoing edges, from a node in a directed graph.

Syntax

node_degree_out([node])

Parameters

NameTypeRequiredDescription
nodestring✔️The reference to a graph node variable in a graph pattern.
No parameters should be passed when used inside all(), any() and map() graph functions, in conjunction with inner_nodes().

Returns

Returns the out-degree of the input node or of all inner nodes, when used inside all(), any() and map() functions in conjunction with inner_nodes().

Examples

The examples in this section show how to use the syntax to help you get started.

Find paths between locations and transportation modes

The following example uses the Locations and Routes data tables to construct a graph that finds paths from a source location to a destination location through a route. It returns the source location name, destination location name, transportation methods along the route, the node_degree_out, which is the number of outgoing edges from the source node (location), and the route_nodes_degree_out, which are the number of outgoing edges from the inner nodes (stopover locations) along the route.

// Locations table (nodes)
let Locations = datatable(LocationName: string, LocationType: string) [
    "New York", "City",
    "San Francisco", "City",
    "Chicago", "City",
    "Los Angeles", "City",
    "Seattle", "Warehouse"
];
// Routes table (edges)
let Routes = datatable(OriginLocationID: string, DestinationLocationID: string, TransportMode: string) [
    "New York", "San Francisco", "Truck",
    "New York", "Chicago", "Train",
    "San Francisco", "Los Angeles", "Truck",
    "Chicago", "Seattle", "Train",
    "Los Angeles", "New York", "Truck",
    "Seattle", "San Francisco", "Train"
];
Routes
| make-graph OriginLocationID --> DestinationLocationID with Locations on LocationName
| graph-match (src)-[route*1..2]->(dest)
project src.LocationName, 
        dest.LocationName, 
        node_degree_out(src),
        route_TransportModes = map(route, TransportMode),
        route_nodes_degree_out = map(inner_nodes(route), node_degree_out())

Output

src_LocationNamedest_LocationNamenode_degree_outroute_TransportModesroute_nodes_degree_out
ChicagoSeattle1[“Train”][]
New YorkChicago2[“Train”][]
Los AngelesNew York1[“Truck”][]
San FranciscoLos Angeles1[“Truck”][]
SeattleSan Francisco1[“Train”][]
New YorkSan Francisco2[“Truck”][]
ChicagoSan Francisco1[“Train”,“Train”][1]
New YorkSeattle2[“Train”,“Train”][1]
New YorkLos Angeles2[“Truck”,“Truck”][1]
San FranciscoNew York1[“Truck”,“Truck”][1]
SeattleLos Angeles1[“Train”,“Truck”][1]
Los AngelesSan Francisco1[“Truck”,“Truck”][2]
Los AngelesChicago1[“Truck”,“Train”][2]

Find employee with no managers

The following example creates a graph to represent the hierarchical relationships between employees and their managers. It uses the graph-match operator to find employees who report to a top-level manager who doesn’t report to anyone else. It uses the node_degree_out function to identify the managers who don’t report to any other manager.

let employees = datatable(name:string, age:long)
[
"Alice", 32,
"Bob", 31,
"Eve", 27,
"Joe", 29,
"Chris", 45,
"Alex", 35,
"Ben", 23,
"Richard", 39,
"Jim", 42,
];
let reports = datatable(employee:string, manager:string)
[
"Bob", "Alice",
"Chris", "Alice",
"Eve", "Bob",
"Ben", "Chris",
"Joe", "Alice",
"Richard", "Bob",
"Alice", "Jim"
];
reports
| make-graph employee --> manager with employees on name
| graph-match (manager)<-[reports]-(employee)
where node_degree_out(manager) == 0
project manager.name, employee.name, di_m=node_degree_in(manager), do_m=node_degree_out(manager), di_e=node_degree_in(employee), do_e=node_degree_out(employee)

Output

manager_nameemployee_namedegree_in_mdegree_out_m
JimAlice10