简体   繁体   中英

Return a graph as nested object in ArangoDB

I wanted to implement a small support ticket system with ArangoDB. I created a collection ticketcategories and wanted to nest them using edges, so I created an edge collection and a graph.

To visualize this, here's an example of the structure: 在此处输入图像描述

And I'd like to return this into a nested object so I can display it in a combobox later, ie like this:

{
  root: {
    categories: [
      bug: {
        categories: [...]
      },
      content: {
        categories: [
          product: {...}
        ]
      },
      feature: {...}
    ]
  }
}

From what I've seen this is not possible with pure AQL, but I don't have much experience with Arango, so I might be wrong.

I tried to perform a normal graph traversal like so:

FOR v, e, p IN 1..4 
   OUTBOUND 'ticketcategories/root'
   GRAPH TicketCategorySubcategories
   OPTIONS { order: 'bfs' }
RETURN p

Since that would give me all paths, but merging those together into a nested object in TypeScript seems dirty. And simply returning the vertices won't give me the relations, so I don't know which subcategories belong to which categories...

Hopefully someone has an idea.

First, returning p (the path) will give you all edges and vertices, so it is possible to determine the relations in JS. However, AQL is good at finding and collecting data, but not great at building a specific JSON document, so the "inelegant" JS could actually be the easiest/cleanest method.

As with any declarative query language, creativity is often required.

My normal approach is to first do it the "stupid" way (very literal/static) and then iterate once you understand how everything fits together and your output is correct.

This example is very static (your graph schema won't change), stepping through the graph one hop at a time. Here, I'm using ZIP() to combine the attribute names to the content in a dynamic way. I know this won't replicate your example JSON schema (it may not even work properly), but it should be illustrative:

RETURN {
    root: {
        categories: (
            FOR vc,ec IN 1 OUTBOUND 'ticketcategories/root'
                GRAPH 'TicketCategorySubcategories'
                LET category = vc.type
                FOR va,ea IN 1 OUTBOUND vc
                    GRAPH 'TicketCategorySubcategories'
                    LET area = va.type
                    LET areas = (
                        FOR vs,es IN 1 OUTBOUND va
                            GRAPH 'TicketCategorySubcategories'
                            LET reasons = (
                                FOR vn,en IN 1 OUTBOUND vs
                                    GRAPH 'TicketCategorySubcategories'
                                    RETURN vn
                            )
                            RETURN ZIP([area],[{ categories: reasons }])
                    )
                    RETURN ZIP([category],[{ categories: areas }])
        )
    }
}

I've used an attribute ( v.type ) to determine the ticket category/area/reason, but this could be done via collection as well (different collections for each category):

LET category = PARSE_IDENTIFIER(v).collection

Or it could be done via an edge property:

LET category = e.type

If you have unique type values, another way to do this could be with the COLLECT statement and aggregation:

COLLECT category = v.type INTO categories
RETURN ZIP([category],[{categories}])

How you define different document types can change your query approach dramatically. For instance, if you have an attribute on each vertex/document, it makes it easy to filter for that. But if you have the definition baked into edges, then you have to query the edges before grabbing the vertices. Either approach isn't bad, just different.

Generally, I have found that when I need to produce a complex JSON document, it's best to use a Foxx service, or at least in-app code with several AQL queries. It's a LOT easier to understand the logic and offers much more control and flexibility.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM