根据用户图书列表的二级邻居(作者)的属性对直接邻居节点(书籍)进行排序?

Sort direct neighbor nodes (books) by attribute of 2nd degree neighbors (authors) for user book list?

来自 Slack 的 agheranimesh:

这是我的图表,名为 LibraryGraph:

我的图表查询:

FOR v, e, p IN 1..2 OUTBOUND "User/001" GRAPH "LibraryGraph"
   SORT p.vertices[2].Name
   RETURN  p.vertices[1]

它没有给我想要的结果。我想要一个按作者姓名 排序的图书列表 ,没有作者的图书应该排在最后(B2、B3、B1、B4、B5)。

重新创建数据的脚本 (arangosh --javascript.execute <file>):

db._createDatabase('Library')
db._useDatabase('Library')

const User = db._create('User')
const Book = db._create('Book')
const Author = db._create('Author')

const User_Book = db._createEdgeCollection('User_Book')
const Book_Author = db._createEdgeCollection('Book_Author')

User.save({ '_key': '001', 'UserName': 'U1' })

Book.save({ '_key': 'B1', 'Name': 'B1' })
Book.save({ '_key': 'B2', 'Name': 'B2' })
Book.save({ '_key': 'B3', 'Name': 'B3' })
Book.save({ '_key': 'B4', 'Name': 'B4' })
Book.save({ '_key': 'B5', 'Name': 'B5' })

Author.save({ '_key': 'A', 'Name': 'A' })
Author.save({ '_key': 'B', 'Name': 'B' })
Author.save({ '_key': 'X', 'Name': 'X' })
Author.save({ '_key': 'Y', 'Name': 'Y' })
Author.save({ '_key': 'Z', 'Name': 'Z' })

User_Book.save({ '_from': 'User/001', '_to': 'Book/B1' })
User_Book.save({ '_from': 'User/001', '_to': 'Book/B2' })
User_Book.save({ '_from': 'User/001', '_to': 'Book/B3' })
User_Book.save({ '_from': 'User/001', '_to': 'Book/B4' })
User_Book.save({ '_from': 'User/001', '_to': 'Book/B5' })

Book_Author.save({ '_from': 'Book/B2', '_to': 'Author/A' })
Book_Author.save({ '_from': 'Book/B3', '_to': 'Author/B' })
Book_Author.save({ '_from': 'Book/B1', '_to': 'Author/X' })
Book_Author.save({ '_from': 'Book/B1', '_to': 'Author/Y' })
Book_Author.save({ '_from': 'Book/B1', '_to': 'Author/Z' })

const graph_module =  require('org/arangodb/general-graph')
const graph = graph_module._create('LibraryGraph')

graph._addVertexCollection('User')
graph._addVertexCollection('Book')
graph._addVertexCollection('Author')

graph._extendEdgeDefinitions(graph_module._relation('User_Book', ['User'], ['Book']))
graph._extendEdgeDefinitions(graph_module._relation('Book_Author', ['Book'], ['Author']))

我建议使用两次遍历,而不是使用具有可变深度 (1..2) 的单一遍历来涵盖有作者和无作者的书籍这两种情况:

FOR book IN OUTBOUND "User/001" GRAPH "LibraryGraph"
    LET author = FIRST(
        FOR author IN OUTBOUND book._id GRAPH "LibraryGraph"
            SORT author.Name
            LIMIT 1
            RETURN author.Name
    ) OR "\uFFFF"
    SORT author
    RETURN book

首先我们从User/001遍历到链接的书籍。然后我们从每本书到链接的作者进行第二次遍历。这可能 return 0、1 或多个作者。子查询将结果限制为按字母顺序排列的第一作者(例如 X,Y,Z 中的 X)和 return 姓名。

在主查询的范围内,我们将作者姓名或回退到排序后最后的值(null 将最先结束,这在此处是不希望的)。然后我们按作者姓名和 return 对书籍进行排序:

实现此结果的另一种方法,但更难理解:

FOR v, e, p IN 1..2 OUTBOUND "User/001" GRAPH "LibraryGraph"
    LET name = p.vertices[2].Name OR "\uFFFF"
    COLLECT book = p.vertices[1] AGGREGATE author = MIN(name)
    SORT author
    RETURN book

遍历 returns 条具有 2 或 3 个顶点的路径...

   [0]         [1]         [2]
User/001 --> Book/B2
User/001 --> Book/B2 --> Author/A
User/001 --> Book/B3
User/001 --> Book/B3 --> Author/B
User/001 --> Book/B4
User/001 --> Book/B5
User/001 --> Book/B1
User/001 --> Book/B1 --> Author/Y
User/001 --> Book/B1 --> Author/X
User/001 --> Book/B1 --> Author/Z

索引 2 处的作者 (p.vertices[2]) 或备用值临时存储在变量 name 中。然后将书的顶点组合在一起以消除重复项(由可变遍历深度引起,returns 例如 001-->B2 但也有更长的路径 001-->B2-->A)。

聚合用于选择具有最低值的作者姓名 (MIN),这通常意味着按字母顺序排在第一位 - 然而,它可能不适用于某些语言和字符集,而 SORT 确实根据设置语言的规则正确排序(每个 DBMS 实例只能是一个)。

分组结果 - 不同的书籍文档 - 按作者姓名和 returned 排序。