原文:ArangoDB High-level operations
以下介紹以下進階操作: FOR:迭代數組的所有元素。 RETURN:產生查詢結果。 FILTER:將結果限制為與任意邏輯條件匹配的元素。 SORT:強制排序一系列已經產生的中間結果。 LIMIT:將結果中的元素數量減少到最多指定的數字,可選擇跳過元素(分頁)。 LET:為變數分配任意值。 COLLECT:按一個或多個組標準對數組進行分組。也可以統計和彙總。 REMOVE:從集合中刪除文檔。 UPDATE:部分更新集合中的文檔。 REPLACE:完全替換集合中的文檔。 INSERT:將新文檔插入到集合中。 UPSERT:更新/替換現有文檔,或在不存在的情況下建立它。 WITH:指定查詢中使用的集合(僅在查詢時開始)。
=====================================================================================
FOR
在FOR關鍵字可以是迭代數組的所有元素。一般文法是:
FOR variableName IN expression
圖形遍曆還有一個特殊的變體:
FOR vertexVariableName, edgeVariableName, pathVariableName IN traversalExpression
對於這種特殊情況,請參見圖形遍曆章節。對於所有其他情況,請閱讀:
運算式返回的每個數組元素都被訪問了一次。需要運算式在所有情況下返回一個數組。空數組也是允許的。當前的數組元素可用於在variableName指定的變數中進一步處理。
FOR u IN users RETURN u
這將遍曆數組使用者的所有元素(注意:在這種情況下,該數組由名為“users”的集合的所有文檔組成),並使變數u中的當前數組元素可用。您在本樣本中未修改,但僅使用RETURN關鍵字推送到結果中。
注意:如下所示,對基於集合的數組進行迭代時,文檔的順序是未定義的,除非使用SORT 語句定義了明確的排序次序。
通過引入的可變FOR可用直到範圍FOR被放置在被關閉。
另一個使用靜態聲明的值數組來迭代的例子:
FOR year IN [ 2011, 2012, 2013 ] RETURN { "year" : year, "isLeapYear" : year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) }
也允許嵌套多個FOR語句。當FOR語句嵌套時, 將建立由各個FOR語句返回的數組元素的交叉乘積。
FOR u IN users FOR l IN locations RETURN { "user" : u, "location" : l }
在這個例子中,有兩個數組迭代:數組使用者的外部迭代 加上數組位置的內部迭代。內部數組遍曆外部數組中的元素多次。對於每次迭代,使用者和位置的當前值可用於變數u和l中的進一步處理。
===================================================================================== RETURN
該RETURN語句可以用於產生查詢的結果。必須在資料選取查詢中的每個塊的末尾指定一個RETURN語句,否則查詢結果將是未定義的。在資料修改查詢的主級使用 RETURN是可選的。
RETURN的一般文法是:
RETURN expression
的表達通過返回RETURN產生在塊中的每個迭代 RETURN語句被放置在,這意味著一個的結果RETURN語句是總是一個數組。如果沒有與查詢匹配的文檔和一個傳回值作為數組返回一個元素,則包含一個空數組。
要從當前迭代的數組中返回所有元素,而不需要修改,可以使用以下簡單的形式:
FOR variableName IN expression RETURN variableName
由於RETURN允許指定運算式,因此可以執行任意計算來計算結果元素。在RETURN放置的範圍內有效任何變數都可用於計算。
要遍曆稱為使用者的一個集合的所有文檔並返回完整的文檔,您可以寫:
FOR u IN users RETURN u
在for迴圈的每次迭代中,將使用者集合的文檔分配給變數u,並在此樣本中未修改返回。要只返回每個文檔的一個屬性,您可以使用不同的返回運算式:
FOR u IN users RETURN u.name
或者返回多個屬性,一個對象可以這樣構造:
FOR u IN users RETURN { name: u.name, age: u.age }
注意:RETURN將關閉當前範圍並消除其中的所有局部變數。在使用子查詢時記住這一點很重要。
還支援動態屬性名稱:
FOR u IN users RETURN { [ u._id ]: u.age }
在此樣本中,每個使用者的文檔_id用作運算式來計算屬性鍵:
[ { "users/9883": 32 }, { "users/9915": 27 }, { "users/10074": 69 }]
結果每個使用者包含一個對象,每個對象具有單個鍵/值對。這通常是不需要的。對於單個對象,將使用者ID映射到年齡,需要將各個結果合并並返回給另一個對象RETURN:
RETURN MERGE( FOR u IN users RETURN { [ u._id ]: u.age })
[ { "users/10074": 69, "users/9883": 32, "users/9915": 27 }]
請記住,如果鍵運算式多次計算相同的值,則只有一個具有重複名稱的鍵/值對可以在MERGE()中存活 。為了避免這種情況,您可以不使用動態屬性名稱,而是使用靜態名稱,並將所有文件屬性作為屬性值返回:
FOR u IN users RETURN { name: u.name, age: u.age }
[ { "name": "John Smith", "age": 32 }, { "name": "James Hendrix", "age": 69 }, { "name": "Katie Foster", "age": 27 }]
返回列表
由於ArangoDB 2.7,RETURN可以後跟DISTINCT關鍵字。該DISTINCT關鍵字將確保傳回值的唯一RETURN語句:
FOR variableName IN expression RETURN DISTINCT expression
如果DISTINCT應用於本身是數組或子查詢的運算式,則DISTINCT不會使每個數組或子查詢結果中的值唯一,而是確保結果僅包含不同的數組或子查詢結果。要使數組或子查詢的結果唯一,只需對數組或子查詢應用DISTINCT。
例如,以下查詢將對其子查詢結果應用DISTINCT,但不在子查詢中:
FOR what IN 1..2 RETURN DISTINCT ( FOR i IN [ 1, 2, 3, 4, 1, 3 ] RETURN i )
這裡我們將有一個兩個迭代的FOR迴圈,每個迴圈都執行一個子查詢。這裡的 DISTINCT應用於兩個子查詢結果。兩個子查詢返回相同的結果值(即[1,2,3,4,1,3]),所以在DISTINCT之後,只有一個值[1,2,3,4,1,3]剩下:
[ [ 1, 2, 3, 4, 1, 3 ]]
如果目標是將DISTINCT應用到子查詢中,則需要將其移動到:
FOR what IN 1..2 LET sub = ( FOR i IN [ 1, 2, 3, 4, 1, 3 ] RETURN DISTINCT i ) RETURN sub
在上述情況下,DISTINCT將使子查詢結果唯一,以便每個子查詢將返回唯一的值數組([1,2,3,4])。由於子查詢執行兩次,頂層沒有DISTINCT,該數組將返回兩次:
[ [ 1, 2, 3, 4 ], [ 1, 2, 3, 4 ]]
注意:結果的順序未定義為RETURN DISTINCT。
注意:如果查詢的頂層沒有FOR 迴圈,則不允許返回DISTINCT。
=====================================================================================
FILTER
該FILTER語句可以被用來限制的結果相匹配的任意的邏輯條件的元素。 一般文法
FILTER condition
條件必須是一個評估為false或true的條件。如果條件結果為假,則跳過當前元素,因此不會進一步處理,而不是結果的一部分。如果條件為真,則不跳過當前元素,並可進一步處理。有關可以在條件下使用的比較子,邏輯運算子等的列表,請參閱運算子。
FOR u IN users FILTER u.active == true && u.age < 39 RETURN u
允許在查詢中指定多個FILTER語句,即使在同一個塊中。如果使用多個FILTER語句,它們的結果將與邏輯AND組合,這意味著包含一個元素的所有過濾條件必須為true。
FOR u IN users FILTER u.active == true FILTER u.age < 39 RETURN u
在上面的例子中,所有數組元素的使用者 具有的屬性 活性值為真,並且具有屬性年齡與值小於39(包括空的)將被包含在結果中。使用者的所有其他元素將被跳過,不包括在RETURN產生的結果中。 有關不存在或空屬性的影響的描述,可參考“ 從集合訪問資料 ”一章。 操作順序
請注意,FILTER語句的位置可能會影響查詢的結果。測試資料中有16個活躍使用者, 例如:
FOR u IN users FILTER u.active == true RETURN u
我們最多可以將結果集限制在5個使用者:
FOR u IN users FILTER u.active == true LIMIT 5 RETURN u
這可能會返回Jim,Diego,Anthony,Michael和Chloe的使用者文檔。返回的是未定義的,因為沒有SORT語句來確保特定的順序。如果我們添加第二個FILTER語句只返回女性...
FOR u IN users FILTER u.active == true LIMIT 5 FILTER u.gender == "f" RETURN u
...它可能只是返回Chloe文檔,因為LIMIT被應用在第二個FILTER之前。不超過5個檔案到達第二個FILTER區塊,並不是所有這些都符合性別標準,儘管收集中有超過5名活躍的女性使用者。通過添加SORT塊可以獲得更確定的結果:
FOR u IN users FILTER u.active == true SORT u.age ASC LIMIT 5 FILTER u.gender == "f" RETURN u
這將返回使用者Mariah和Mary。如果按照DESC順序按年齡排序,則返回Sophia,Emma和Madison文檔。一個過濾器一後 LIMIT不是很常見不過了,你可能想這樣的查詢,而不是:
FOR u IN users FILTER u.active == true AND u.gender == "f" SORT u.age ASC LIMIT 5 RETURN u
放置FILTER塊的重要性允許這個單個關鍵字可以承擔兩個SQL關鍵字WHERE以及HAVING的角色。因此,AQL的FILTER與COLLECT彙總一起使用與任何其他中間結果,文件屬性等相同。 =====================================================================================
SORT
所述SORT語句將強制在當前塊中已經產生的中間結果的數組進行排序。SORT允許指定一個或多個排序標準和方向。一般文法是:
SORT expression direction
指定方向是可選的。排序的預設(隱式)方向是升序。要明確指定排序方向,可以使用關鍵字ASC(升序)和DESC。可以使用逗號分隔多個排序標準。
注意:在迭代基於集合的數組時,除非使用SORT定義明確的排序次序,否則始終未定義文檔的順序。
FOR u IN users SORT u.lastName, u.firstName, u.id DESC RETURN u
請注意,常量SORT運算式可用於指示不需要特定排序次序。在最佳化過程中,AQL最佳化程式將最佳化常量SORT運算式,但是如果最佳化程式不需要考慮任何特定的排序次序,則可以顯式指定它們可以進一步最佳化。
=====================================================================================
LIMIT
LIMIT語句允許切片使用位移和計數結果數組。它將結果中的元素數量減少到最多指定的數字。遵循LIMIT的兩種一般形式:
LIMIT countLIMIT offset, count
第一種形式允許僅指定計數值,而第二種形式允許指定位移量和計數值。第一種形式與使用位移值為0的第二種形式相同。
FOR u IN users LIMIT 5 RETURN u
以上查詢返回使用者集合的前五個文檔。也可以寫出LIMIT 0, 5相同的結果。實際返回的檔案是相當隨意的,因為沒有指定明確的排序次序。因此,通常需要一個SORT操作。
該位移值指定從結果許多元素將被跳過。它必須為0或更大。該計值指定有多少元素應該至多包含在結果中。
FOR u IN users SORT u.firstName, u.lastName, u.id DESC LIMIT 2, 5 RETURN u
在上面的樣本中,使用者的文檔被排序,前兩個結果被跳過,並返回下一個五個使用者文檔。
請注意,變數和運算式不能用於位移和計數。它們的值在查詢編譯時間必須知道,這意味著您只能使用數字文字和綁定參數。
如果使用LIMIT與查詢中的其他動作有關。 特別是FILTER之前的LIMIT操作可以顯著地改變結果,因為操作按照它們在查詢中寫入的順序執行。有關詳細樣本,請參閱FILTER。
=====================================================================================
LET
該LET語句可用於分配給一個變數的任意值。然後在LET語句放置的範圍中引入該變數。
一般文法是:
LET variableName = expression
變數在AQL中是不可變的,這意味著它們不能被重新分配:
LET a = [1, 2, 3] // initial assignmenta = PUSH(a, 4) // syntax error, unexpected identifierLET a = PUSH(a, 4) // parsing error, variable 'a' is assigned multiple timesLET b = PUSH(a, 4) // allowed, result: [1, 2, 3, 4]
LET語句主要用於聲明複雜計算,並避免在查詢的多個部分重複計算相同的值。
FOR u IN users LET numRecommendations = LENGTH(u.recommendations) RETURN { "user" : u, "numRecommendations" : numRecommendations, "isPowerUser" : numRecommendations >= 10 }
在上述樣本中,使用LET語句計算推薦數量,從而避免在RETURN語句中計算兩次值。
LET的另一個用例是在子查詢中聲明一個複雜的計算,使整個查詢更易讀。
FOR u IN users LET friends = ( FOR f IN friends FILTER u.id == f.userId RETURN f ) LET memberships = ( FOR m IN memberships FILTER u.id == m.userId RETURN m ) RETURN { "user" : u, "friends" : friends, "numFriends" : LENGTH(friends), "memberShips" : memberships } ========================================================================================
COLLECT
所述COLLECT關鍵字可以由一個或多個基團的標準被用於組的陣列。
該COLLECT語句將消除當前範圍內的所有局部變數。在COLLECT之後,只有COLLECT本身引入的變數才可用。
COLLECT的一般文法是:
COLLECT variableName = expression optionsCOLLECT variableName = expression INTO groupsVariable optionsCOLLECT variableName = expression INTO groupsVariable = projectionExpression optionsCOLLECT variableName = expression INTO groupsVariable KEEP keepVariable optionsCOLLECT variableName = expression WITH COUNT INTO countVariable optionsCOLLECT variableName = expression AGGREGATE variableName = aggregateExpression optionsCOLLECT AGGREGATE variableName = aggregateExpression optionsCOLLECT WITH COUNT INTO countVariable options
options 在所有變體中都是可選的。 分組文法
COLLECT的第一個文法形式只能通過運算式中指定的定義組標準對結果進行分組。為了進一步處理COLLECT產生的結果,引入了一個新的變數(由variableName指定)。此變數包含組值。
以下是一個樣本查詢,可以在u.city中找到不同的值,並使其在可變城市中可用:
FOR u IN users COLLECT city = u.city RETURN { "city" : city }
第二種形式與第一種形式相同,但另外還引入了一個變數(由groupsVariable指定),該變數包含落入組中的所有元素。這樣做的工作如下:groupsVariable變數是一個數組,包含與組中所有元素一樣多的數組。該數組的每個成員都是一個JSON對象,其中在AQL查詢中定義的每個變數的值都綁定到相應的屬性。請注意,它考慮在COLLECT語句之前定義的所有變數,但不考慮頂級(在任何FOR之外)中的所有變數,除非COLLECT語句本身在頂級,在這種情況下所有變數都被採用。
FOR u IN users COLLECT city = u.city INTO groups RETURN { "city" : city, "usersInCity" : groups }
在上面的例子中,數組使用者將按屬性城市分組 。結果是一個新的文檔數組,每個不同的u.city值有一個元素。每個城市的原始陣列(這裡:使用者)的元素在變數組中可用。這是因為INTO條款。
COLLECT還允許指定多個組標準。個別組標準可以用逗號分隔:
FOR u IN users COLLECT country = u.country, city = u.city INTO groups RETURN { "country" : country, "city" : city, "usersInCity" : groups }
在上述樣本中,陣列使用者按省/地區按城市分組,並且對於國家和城市的每個不同組合,將返回使用者。 丟棄過時的變數
COLLECT的第三種形式允許 使用任意的projectionExpression重寫groupsVariable的內容:
FOR u IN users COLLECT country = u.country, city = u.city INTO groups = u.name RETURN { "country" : country, "city" : city, "userNames" : groups }
在上面的例子中,只有projectionExpression是u.name。因此,只有這個屬性被複製到每個文檔的groupsVariable中。這可能比將所有變數從範圍複製到groupsVariable更有效,就像沒有projectionExpression一樣。
INTO中的運算式也可用於任意計算:
FOR u IN users COLLECT country = u.country, city = u.city INTO groups = { "name" : u.name, "isActive" : u.status == "active" } RETURN { "country" : country, "city" : city, "usersInCity" : groups }
COLLECT還提供了一個可選的KEEP子句,可用於控制哪些變數將被複製到建立的變數中INTO。如果沒有指定KEEP子句,則範圍中的所有變數將作為子屬性複製到groupsVariable中。這是安全的,但如果範圍中有很多變數或變數包含大量資料,則可能會對效能產生負面影響。
以下樣本將複製到groupsVariable中的變數限制 為僅命名。範圍內的變數u和someCalculation也不會被複製到groupsVariable,因為它們沒有列在KEEP子句中:
FOR u IN users LET name = u.name LET someCalculation = u.value1 + u.value2 COLLECT city = u.city INTO groups KEEP name RETURN { &qu