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

时间:2017-09-01 12:41:36

标签: sorting graph arangodb graph-traversal aql

通过Slack agheranimesh:

这是我的图表,名为 LibraryGraph

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 个答案:

答案 0 :(得分:1)

我建议使用两次遍历,而不是使用具有可变深度(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遍历到链接的书籍。然后我们从每本书到链接作者进行第二次遍历。这可能会返回0,1或多个作者。子查询将结果限制为按字母顺序排列的第一作者(例如X,X,Y,Z中的X)并返回名称。

在主查询的范围内,我们将作者姓名或后备值视为最后一个值,如果已排序(null将首先结束,这里不需要)。然后我们按作者名称对书籍进行排序并返回:

Query result

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

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

遍历返回带有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中。然后将书籍顶点组合在一起以消除重复(由变量遍历深度引起,例如001-->B2,但也返回更长的路径001-->B2-->A)。

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

分组结果 - 不同的图书文档 - 按作者姓名排序并返回。