【前情提要】
在上一回中,我們只集中在同個 Collection 內的資料。那接著,我們就要透過 Edge 找到所有關聯的資料,並透過集合(set)合併或篩選資料。
【重點整理】
- 透過 _from 與 _to 屬性取得 Edge 的連結
- 集合不帶有排序功能,先排序再結合也會亂掉
【預計內容】
- Edge 的指向
- 集合(聯集、交集與差集)
- 陣列的儲存與刪除
【主要內容】
1. Edge 的指向
回想起 Edge Collection,分別有 _from 與 _to 兩個資料指向資料的 _id,藉由這個屬性,我們也能夠獲取到兩端的資料。那這邊,我先做好了資料的準備,標註兩位朋友的各一幅畫。
LET specified_artist_id = "artist_vertices/366"
FOR e IN artist_edges
FILTER e._from == specified_artist_id
LET friend_id = e._to
LET friend = DOCUMENT(friend_id)
FOR artwork_edge IN work_edges
FILTER artwork_edge._from == friend_id
LET artwork_id = artwork_edge._to
LET artwork_doc = DOCUMENT(artwork_id)
RETURN {
friend: friend.full_name,
artwork_name: artwork_doc.name,
style: artwork_doc.style
}
可以看到,我們只選到在 Edge 中,某畫家(_from)有關的朋友們(_to)的資料
2. 集合(聯集、交集與差集)
在上方,我們透過 Edge 的關聯打印出某畫家的朋友們的作品。那如果希望將畫家本人的作品也加入進來,又只能回傳一次怎麼辦?這時就可以依靠集合概念中的聯集 UNION,組成 JSON 回傳。
那在範例中,可以看到我們分別用兩個變數,個別儲存作家本人與朋友們的資料,最後才統合資料。最後能看到,我們多出(有登記的)Claude Monet 的三個作品。
LET specified_artist_id = "artist_vertices/366"
LET works_of_artist = (
FOR e IN work_edges
FILTER e._from == specified_artist_id
LET artwork_doc = DOCUMENT(e._to)
RETURN {
artist: DOCUMENT(specified_artist_id).full_name,
artwork_name: artwork_doc.name,
style: artwork_doc.style
}
)
LET works_of_friend = (
FOR e IN artist_edges
FILTER e._from == specified_artist_id
LET friend = DOCUMENT(e._to)
FOR work_edge IN work_edges
FILTER work_edge._from == e._to
LET artwork_doc = DOCUMENT(work_edge._to)
RETURN {
artist: friend.full_name,
artwork_name: artwork_doc.name,
style: artwork_doc.style
}
)
RETURN UNION(works_of_artist, works_of_friend)
而交集是指多個集合中共同擁有的部分。那再來,我們透過所有作品與作家作品來呈現交集,透過 INTERSECTION 從所有作品塞出作家的作品。
LET specified_artist_id = "artist_vertices/366"
LET works_of_artist = (
FOR e IN work_edges
FILTER e._from == specified_artist_id
LET artwork_doc = DOCUMENT(e._to)
RETURN {
artwork_name: artwork_doc.name,
style: artwork_doc.style
}
)
LET works_of_all = (
FOR work IN work_vertices
RETURN {
artwork_name: work.name,
style: work.style
}
)
RETURN INTERSECTION(works_of_artist, works_of_all)
那相對的,差集是指集合中不同的資料。而在 AQL 語法中,則是用相對於交集的 OUTERSECTION 代表。那在下方的範例中,那為了方便證明少去上方的三筆資料,我們直接透過畫作名稱做查詢。
LET specified_artist_id = "artist_vertices/366"
LET works_of_artist = (
FOR e IN work_edges
FILTER e._from == specified_artist_id
LET artwork_doc = DOCUMENT(e._to)
RETURN {
artist_id: artwork_doc.artist_id,
artwork_name: artwork_doc.name,
style: artwork_doc.style
}
)
LET works_of_all = (
FOR work IN work_vertices
RETURN {
artist_id: work.artist_id,
artwork_name: work.name,
style: work.style
}
)
LET set = OUTERSECTION(works_of_artist, works_of_all)
LET sorted_results = (
FOR result IN set
SORT result.artist_id ASC
RETURN result
)
RETURN sorted_results
那各位應該有看到在上方的最後我依照作家的 ID 逐個重新排序,這是因為先 SORT 再做集合,照集合的整理特性排序很常會亂掉。
3. 陣列的儲存與刪除
在 AQL 中,其針對陣列的增減類似於 JavaScript 的概念,依樣式透過虛擬的資料結構來進行儲存與刪除,也就是常見的 stack 與 queue 型態。
那這邊我們就不使用複雜的資料,用數字陣列方便各位理解概念。那以 stack 的概念,分別有 PUSH (+) 與 POP (-) 兩個方法,是針對陣列的最末端進行處理。類似的道理之下,我們會再用 queue 的概念操作 UNSHIFT (+) 與 SHIFT (-),針對前端做處理。
那依照下方的 PUSH,我們將 4 加入到末端,變成 [1, 2, 3, 4]
RETURN PUSH([1, 2, 3], 4)
此時,我們再透過 POP,剔除剛加入的數字。但不同於一般的程式語言只回傳脫離的 4,為了 query 的完整性,回傳的會是 [1, 2, 3]
RETURN POP([1, 2, 3, 4])
用一樣的架構去呼叫 UNSHIFT,回傳的結果是 [4, 1, 2, 3]
RETURN UNSHIFT([1, 2, 3], 4)
而接著 SHIFT 排序好的陣列,則會變為 [2, 3, 4]
RETURN SHIFT([1, 2, 3, 4])
【後話】
那在這篇中,我們簡單的呈現如何利用 Edge 取得橫跨的資料。並藉由集合與陣列,講述簡單的資料合併方式。那在下一篇,我將以常說的 CRUD 進行資料的增加修改。那麼,我們下期再會。
【參考資料】
[1] Array Function
https://docs.arangodb.com/3.11/aql/functions/array/