简体   繁体   English

在 ArangoDB 中返回嵌套 object 的图

[英]Return a graph as nested object in ArangoDB

I wanted to implement a small support ticket system with ArangoDB.我想用 ArangoDB 实现一个小型支持票系统。 I created a collection ticketcategories and wanted to nest them using edges, so I created an edge collection and a graph.我创建了一个集合ticketcategories并希望使用边将它们嵌套,因此我创建了一个边集合和一个图形。

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:我想将其返回到嵌套的 object 中,以便稍后在 combobox 中显示它,即:

{
  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.据我所知,这对于纯 AQL 是不可能的,但我对 Arango 没有太多经验,所以我可能是错的。

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.因为那会给我所有路径,但是将它们合并到 TypeScript 中的嵌套 object 似乎很脏。 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.首先,返回p (路径)会给你所有的边和顶点,所以可以确定 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.然而,AQL 擅长查找和收集数据,但不擅长构建特定的 JSON 文档,因此“不优雅”的 JS 实际上可能是最简单/最干净的方法。

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.我通常的方法是首先以“愚蠢”的方式(非常文字/静态)进行操作,然后在您了解所有内容如何组合在一起并且您的 output 正确后进行迭代。

This example is very static (your graph schema won't change), stepping through the graph one hop at a time.这个例子非常 static(你的图表模式不会改变),一次一步地通过图表。 Here, I'm using ZIP() to combine the attribute names to the content in a dynamic way.在这里,我使用ZIP()以动态方式将属性名称组合到内容中。 I know this won't replicate your example JSON schema (it may not even work properly), but it should be illustrative:我知道这不会复制您的示例 JSON 模式(它甚至可能无法正常工作),但它应该是说明性的:

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):我使用了一个属性 ( v.type ) 来确定票证类别/区域/原因,但这也可以通过收集来完成(每个类别的 collections 不同):

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:如果您有唯一的type值,另一种方法是使用COLLECT语句和聚合:

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.通常,我发现当我需要生成复杂的 JSON 文档时,最好使用 Foxx 服务,或者至少使用带有多个 AQL 查询的应用程序内代码。 It's a LOT easier to understand the logic and offers much more control and flexibility.它更容易理解逻辑并提供更多的控制和灵活性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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