Reputation: 8762
I'm working with ArangoDB and have a graph traversal scenario where I need to skip a specific node based on a property, but still infer an indirect connection (edge) between two other nodes. My graph contains edges from A to B and B to C, but not directly from A to C. Node B has a property `ShouldSkip` set to true, and I want to skip it in the traversal results.
The desired outcome is to get edges: edge from A to C (inferred), and nodes: A and C, effectively skipping B in the results. However, since there's no direct edge from A to C in the graph, I'm not sure how to represent this in the query results.
Here's my current AQL query:
LET startNodeId = 'A' // Example start node
LET depth = 2
LET startNode = DOCUMENT('nodeCollectionName', startNodeId)
LET traversalResults = (
FOR v, e IN 1..depth OUTBOUND startNode GRAPH 'graphName'
FILTER v.ShouldSkip != true
LIMIT 100
RETURN {node: v, edge: e}
)
LET allNodes = (
FOR tr IN traversalResults
RETURN tr.node
)
LET allEdges = (
FOR tr IN traversalResults
RETURN tr.edge
)
RETURN {StartNode: startNode, Nodes: UNIQUE(FLATTEN(allNodes)), Edges: UNIQUE(FLATTEN(allEdges))}
How can I adjust this query to infer an edge from A to C (only! without A to B and B to C), or is there a better approach to achieve this in ArangoDB (like while in indexing create a virtual edge of A to C - much less preferable)?
Effectively I would like the response to be: nodes: [A,C] edges: [{_from: A, _to: C}]
Upvotes: 1
Views: 138
Reputation: 8762
Another solution,
Full code:
// Define the starting node ID and the depth for the graph traversal
LET startNodeId = @startNode
LET depth = @depth
// Retrieve the document (node) corresponding to the startNodeId from the specified collection
LET startNode = DOCUMENT(@nodeCollectionName, startNodeId)
// Step 1: Find all paths from the start node up to the specified depth in the graph
LET allPaths = (
FOR v, e, p IN 1..depth ANY startNode GRAPH @graphName
// Return each path found during the traversal
RETURN p
)
// Step 2: Filter the paths' nodes based on the 'ShouldSkip' property
LET filteredPaths = (
FOR path IN allPaths
// Filter out vertices in each path where 'ShouldSkip' is false
LET filteredVertices = (FOR vertex IN path.vertices FILTER vertex.ShouldSkip == false RETURN vertex)
// Return the filtered vertices along with the original path
RETURN {{vertices: filteredVertices, originalPath: path }}
)
// Step 3: Infer the edges of the filtered nodes paths
LET inferredEdges = FLATTEN(
FOR filteredPath IN filteredPaths
// Create new edges between consecutive visible vertices
LET edges = (
FOR i IN 0..LENGTH(filteredPath.vertices) - 2
LET startVertex = filteredPath.vertices[i]
LET endVertex = filteredPath.vertices[i + 1]
// Return a new edge from startVertex to endVertex
RETURN {{_from: startVertex._id, _to: endVertex._id }}
)
// Flatten the list of edges for all paths
RETURN edges
)
// Deduplicate the inferred edges
LET distinctEdges = UNIQUE(inferredEdges)
// Extract and deduplicate nodes from the filtered paths
LET allNodes = FLATTEN(
FOR path IN filteredPaths
// Extract vertices from each filtered path
RETURN path.vertices
)
// Deduplicate the nodes
LET distinctNodes = UNIQUE(allNodes)
// Return the start node, distinct nodes, and distinct edges
RETURN
{{
StartNode: startNode,
Nodes: distinctNodes,
Edges: distinctEdges
}}
Upvotes: 1