ArangoDB AQL中(n)数组的交集

Joa*_*ild 3 arangodb aql

场景是这样的:我有一个包含项目的ArangoDB集合,以及另一个包含标签的集合.我正在使用图表,我有一个名为"Contains"的边集合连接项目和标签.一个项目有多个标签.

现在我正在尝试搜索包含多个标签的项目.例如,包含标签"photography","portrait"和"faces"的项目.

我的一般方法是从每个标记顶点开始图遍历,并找到与该标记相关的项.那部分工作正常.我得到了一个项目清单.

但我的任务的最后一部分是建立所有列表的交集,以便找到包含所有指定标记的项目.我无法弄清楚如何做到这一点.

我想做的是这样的:

let tagnames = SPLIT(@tagnames,',')
let tagcollections = (
    FOR tagname IN tagnames
    LET atag = (FOR t IN tags FILTER LOWER(t.text)==LOWER(tagname) RETURN t)
    let collections = (FOR v IN 1..1 INBOUND atag[0] Contains RETURN v)

    RETURN { tag: atag, collections: collections }
)

RETURN INTERSECTION(tagcollections)
Run Code Online (Sandbox Code Playgroud)

但是,它不起作用:INTERSECTION函数不能在单个列表上工作,而是在多个项目上工作,如下所示:INTERSECTION(listA,listB,listC ...).

如何在FOR ... RETURN块中找到列表的交集?

CoD*_*anX 5

ArangoDB 3.0引入特殊阵列比较运算符(ANY,ALL,NONE).ALL IN可用于测试左侧数组中的每个元素是否也在右侧数组中:

[ "red", "green", "blue" ] ALL IN [ "purple", "red", "blue", "green" ]
// true
Run Code Online (Sandbox Code Playgroud)

请注意,这些运算符尚不能使用索引.给定一个将标记直接嵌入到文档中的数据模型,一种解决方法是使用索引查找包含其中一个标记的所有文档(例如,获取第一个元素["red","green","blue"][0]),以在没有完整集合扫描的情况下减少结果集,然后ALL IN如果其他标记也在列表中,则过滤后:

LET tagsToSearchFor = [ "red", "green", "blue" ]
FOR doc IN coll
  FILTER tagsToSearchFor[0] IN doc.tags[*] // array index
  FILTER tagsToSeachFor ALL IN doc.tags
  RETURN doc
Run Code Online (Sandbox Code Playgroud)

ALL IN也可以使用单独的标记集合为您的数据模型使用,但您将无法使用上述索引.例如:

FOR doc IN documents
    LET tags = (
        FOR v IN INBOUND doc contains
            RETURN v._key
    )
    FILTER ["red", "green", "blue"] ALL IN tags
    RETURN MERGE(doc, {tags})
Run Code Online (Sandbox Code Playgroud)

或者,如果要使用标记开始遍历并使用基于交集的方法:

LET startTags = ["red", "green", "blue"] // must exist
LET ids = (
    FOR startTag IN DOCUMENT("tags", startTags)
        RETURN (
            FOR v IN OUTBOUND startTag contains
                RETURN v._id
        )
)
LET docs = APPLY("INTERSECTION", ids)

FOR doc IN DOCUMENT(docs)
    RETURN MERGE(doc, {
        tags: (FOR tag IN INBOUND doc contains RETURN tag._key)

    })
Run Code Online (Sandbox Code Playgroud)