5

I want to return a list of all unique edges and all unique vertices met during a graph traversal query. This gives me exactly the result I want, but I'm executing the same query twice:

    LET eResults = (    
        FOR v,e
            IN 1..2
            ANY "entities/198593"
            relations
            OPTIONS { uniqueEdges: "path", bfs: true }
            RETURN DISTINCT KEEP(e, "_key", "_from", "_to", "type")
    )
    LET vResults = (
        FOR v,e
            IN 1..2
            ANY "entities/198593"
            relations
            OPTIONS { uniqueEdges: "path", bfs: true }
            RETURN DISTINCT KEEP(v, "_key", "name")
    )
    RETURN { edges: eResults, vertices: vResults}

The query result, containing each edge and vertice exactly once:

    [
      {
        "edges": [
          {
            "_from": "entities/198593",
            "_key": "391330",
            "_to": "entities/198603",
            "type": 300
          },
          {
            "_from": "entities/198593",
            "_key": "391390",
            "_to": "entities/198477",
            "type": 110
          },
          ...
        ],
        "vertices": [
          { "_key": "198603", "name": "A" },
          { "_key": "198477", "name": "B" },
          ...
        ]
      }
    ]

How can I achieve the same result (unique vertices and unique edges) with one query?

PS: The results are wrapped in an array, any idea why? How to avoid this?

now
  • 4,772
  • 2
  • 24
  • 26

3 Answers3

3

You can try 2 things, the first is a half-solution:

{uniqueEdges: "path", uniqueVertices: "global"} 

However you need to remove bfs: true I think.

After this, you would need to dedupe in javascript in the browser, or if you're using foxx you can do it in the API call before returning the result.

However, if you are using foxx, you can use the below JS in your service index.js file. Or you can just use the uniqueList function in your application/website etc. And you will have unique lists.

  1. create a function to get a unique array of objects based on their _id property

  2. do the call

  3. after the call, run the result through the uniqueList function then return the result

I.e.

function uniqueList(nonuniquelist){ 
    var u_list = []
    var u_edge_out_list = []
    //Go through each array and create unique set
    for(var w = 0; w < nonuniquelist.length; w++) {
        console.log()
        if (nonuniquelist[w] != null){
            if (u_list.indexOf(nonuniquelist[w]['_id']) <= 0){
                u_edge_out_list.push(nonuniquelist[w])
                console.log(nonuniquelist[w])
                u_list.push(nonuniquelist[w]['_id'])
                }
        }
    }
    return (u_edge_out_list);
}

router.get("/almost_unique_things",function(req,res){
   var bind_variables(entity_id: "entities/198593" );
   var aql = 
    `LET eResults = ( 
        FOR v,e
            IN 1..2
            ANY @entity_id
            relations
            OPTIONS { uniqueEdges: "path", bfs: true }
            RETURN DISTINCT KEEP(e, "_key", "_from", "_to", "type")
    )
    LET vResults = (
        FOR v,e
            IN 1..2
            ANY @entity_id"
            relations
            OPTIONS { uniqueEdges: "path", bfs: true }
            RETURN DISTINCT KEEP(v, "_key", "name")
    )
    RETURN { edges: eResults, vertices: vResults}`

    var results = db._query(aql,bind_variables).toArray();
    var uniqueEdges = uniqueList(edges);
    var uniqueVertices = uniqueList(vertices);
    RETURN { edges: uniqueEdges , vertices: uniqueVertices }
 });
Greggers
  • 131
  • 1
  • 6
1

You're close...

With the line FOR v,e you have access to one more variable, p.

Try this:

    FOR v,e,p
        IN 1..2
        ANY "entities/198593"
        relations
        OPTIONS { uniqueEdges: "path", bfs: true }
        RETURN DISTINCT p

Edit: It's possible to RETURN DISTINCT p if you want to remove duplicate paths, but I'm not sure how you'd get duplicate paths if you have uniqueEdges: "path".

See if that helps, if not, post a reply and we'll see what we can do.

David Thomas
  • 2,264
  • 2
  • 18
  • 20
  • 1
    Thanks, but the problem with p is that it sends duplicate nodes and edges. The result is 1600 lines of JSON instead of 200 in one example without KEEP(). How to de-duplicate those edges and vertices? – now Apr 13 '19 at 13:16
1
//Starting from the path result above:
    let path =(FOR v,e,p
            IN 1..2
            ANY "entities/198593"
            relations
            OPTIONS { uniqueEdges: "path", bfs: true }
            RETURN DISTINCT p)
    
//compress, flatten and return first record out of array result the unique //vertices and edges:
          let vertices = first(return unique(flatten(path[**].vertices)))
          let edges = first(return unique(flatten(path[**].edges)))

//combine into a single graph object & return (as you've done above): 
    return {"vertices":vertices, "edges":edges}

To me this is an overly complex exercise for such an obvious request from a graph db. I do not comment on the options added in the previous answer.

Sailor
  • 13
  • 4