0

My webapp needs to display several sorted lists of document attributes in a graph. These are hours, cycles, and age.

I have an AQL query that beautifully traverses the graph and gets me all the data my app needs in 2 ms. I'm very impressed! But I need it sorted for each graph. The query currently returns an array of json objects that contain all three of the attributes and the id for which they apply. Awesome. The query also very easily sorts on one of the attributes.

My problem is: I need to have a sorted list of all three, and would prefer not to query the database three times since the data is all in the same documents my traversal returned.

I would like to return three sorted arrays of json objects: one containing hours and the id, one containing cycles and the id, and one containing age and the id. This way, my graphs can easily display all three graphs without client-side sorting.

HTTP requests themselves are time consuming although the database is very fast, which is why I'd like to pull all three at once, as the data itself is small.

My current query is a simple graph traversal:

for v, e, p in outbound startNode graph 'myGraph'
    filters & definitions...
    sort v.hours desc
    return {"hours": v.hours, "cycles": v.cycles, "age": v.age, "id": v.id}

Is there an easy way I can tell Arango to return me this structure?

{
 [
  {
   "id": 47,
   "hours": 123
  },
  {
   "id": 23,
   "hours": 105
  }...
 ],
 [
  {
   "id": 47,
   "cycles": 18
  },
  {
   "id": 23,
   "cycles": 5
  }...
 ],
 [
  {
   "id": 47,
   "age": 4.2
  },
  {
   "id": 23,
   "age": 0.9
  }
 ]
}

Although the traversal is fast, I would prefer if I didn't have to re-traverse the graph three times to do it, if possible.

Community
  • 1
  • 1
Nate Gardner
  • 1,577
  • 1
  • 16
  • 37

2 Answers2

1

My solution:

let data = (for v, e, p in outbound startNode graph 'myGraph'
                filters & definitions...
                return {"hours": v.hours, "cycles": v.cycles, "age": v.age, "id": v.id})
let byHours = (for thing in data
                   sort thing.hours desc
                   return {"hours": thing.hours, "id": thing.id})
let byCycles = (for thing in data
                    sort thing.cycles desc
                    return {"cycles": thing.cycles, "id": thing.id})
let byAge = (for thing in data
                 sort thing.age desc
                 return {"age": thing.age, "id": thing.id})
return {"hours": byHours, "cycles": byCycles, "age": byAge}
Nate Gardner
  • 1,577
  • 1
  • 16
  • 37
  • You could sort by hours for `data`, so you don't have the traversal and 3 sub-queries for sorting, but only one traversal with a sort, plus 2 sub-queries for different sorting order. It doesn't make much of a difference though I guess. – CodeManX Aug 23 '16 at 16:27
  • I think that would be faster, since the hours, cycles, and age sort orders are very similar. Sorting from the arbitrary order three times seems like it would take longer. – Nate Gardner Aug 23 '16 at 21:42
  • Okay, I tried it that way, too. The way I have above takes 3ms and presorting by hours, then sorting cycles and age based on the presorted list takes 5ms. I didn't expect that, but the sort is actually slower with this optimization. – Nate Gardner Aug 24 '16 at 00:15
1

I'm not sure how this compares against your solution performance-wise, but the most obvious solution would be to traverse once and then create three sorted results like this:

LET nodes = (
  FOR v, e, p IN OUTBOUND startNode GRAPH 'myGraph'
  FILTER ...
  RETURN v
)
RETURN {
  hours: (
    FOR n IN nodes
    SORT n.hours DESC
    RETURN KEEP(n, ['hours', 'id'])
  ),
  cycles: (
    FOR n IN nodes
    SORT n.cycles DESC
    RETURN KEEP(n, ['cycles', 'id'])
  ),
  age: (
    FOR n IN nodes
    SORT n.age DESC
    RETURN KEEP(n, ['age', 'id'])
  )
}

This would traverse the graph only once but sort the result three times.

Alan Plum
  • 10,814
  • 4
  • 40
  • 57