ArangoDB查詢語言(AQL) 基本語法&用法

原文連接ios

我的博客-歡迎訪問git

ArangoDB查詢語言(AQL)相似於結構化查詢語言(SQL) 在它的目的。二者都支持讀取和修改集合數據,但AQL不支持數據定義操做,例如建立和刪除數據庫,集合和索引。github

雖然有些關鍵字重疊,但AQL語法與SQL不一樣。例如,SQL WHERE和AQL FILTER子句是等效的,由於它們都定義了返回結果的條件。可是,SQL使用預約義的序列來肯定WHERE語句必須在哪裏出現。在AQL中,子句從左到右執行,所以FILTER查詢中子句的位置決定了它的優先級。數據庫

儘管有這些差別,任何具備SQL背景的人都應該沒有學習AQL的困難。express

ArangoDB

1、數據預覽

本次使用的數據共有43條,每條數據包含姓氏、年齡、活動狀態和特徵等六個字段 數組

ArangoDB

其中每一個特徵都有一個隨機字母做爲文檔密鑰。特質標籤有英文和德文。 bash

ArangoDB

地點由地名和經緯度組成: 函數

ArangoDB

2、基本的CRUD

建立集合:

在建立文檔以前,須要創造一個放置它的集合,集合能夠經過Web界面,arangosh或驅動程序來建立。AQL沒法建立集合。學習

ArangoDB

單擊Web界面中的COLLECTIONS,而後單擊Add Collection並鍵入 Charactersname。使用保存確認。新集合就出如今了列表中。ui

插入單個對象:

使用AQL插入文檔

ArangoDB

INSERT {
    "name": "Ned",
    "surname": "Stark",
    "alive": true,
    "age": 41,
    "traits": ["A","H","C","N","P"]
} INTO Characters

複製代碼

語法:

INSERT document INTO collectionName

該文檔是一個對象,由屬性鍵和值對組成。屬性鍵的引號在AQL中是可選的。鍵老是字符串,而屬性值能夠有不一樣的類型:

  • null
  • boolean (true, false)
  • number (integer and floating point)
  • string
  • array
  • object

批量插入對象:

AQL不容許INSERT在單個查詢中針對同一集合的多個操做。可是可使用FOR循環體,插入多個文檔。

LET data = [
    { "name": "Robert", "surname": "Baratheon", "alive": false, "traits": ["A","H","C"] },
    { "name": "Jaime", "surname": "Lannister", "alive": true, "age": 36, "traits": ["A","F","B"] },
    { "name": "Catelyn", "surname": "Stark", "alive": false, "age": 40, "traits": ["D","H","C"] },
    { "name": "Cersei", "surname": "Lannister", "alive": true, "age": 36, "traits": ["H","E","F"] },
    { "name": "Daenerys", "surname": "Targaryen", "alive": true, "age": 16, "traits": ["D","H","C"] },
    { "name": "Jorah", "surname": "Mormont", "alive": false, "traits": ["A","B","C","F"] },
    { "name": "Petyr", "surname": "Baelish", "alive": false, "traits": ["E","G","F"] },
    { "name": "Viserys", "surname": "Targaryen", "alive": false, "traits": ["O","L","N"] },
    { "name": "Jon", "surname": "Snow", "alive": true, "age": 16, "traits": ["A","B","C","F"] },
    { "name": "Sansa", "surname": "Stark", "alive": true, "age": 13, "traits": ["D","I","J"] },
    { "name": "Arya", "surname": "Stark", "alive": true, "age": 11, "traits": ["C","K","L"] },
    { "name": "Robb", "surname": "Stark", "alive": false, "traits": ["A","B","C","K"] },
    { "name": "Theon", "surname": "Greyjoy", "alive": true, "age": 16, "traits": ["E","R","K"] },
    { "name": "Bran", "surname": "Stark", "alive": true, "age": 10, "traits": ["L","J"] },
    { "name": "Joffrey", "surname": "Baratheon", "alive": false, "age": 19, "traits": ["I","L","O"] },
    { "name": "Sandor", "surname": "Clegane", "alive": true, "traits": ["A","P","K","F"] },
    { "name": "Tyrion", "surname": "Lannister", "alive": true, "age": 32, "traits": ["F","K","M","N"] },
    { "name": "Khal", "surname": "Drogo", "alive": false, "traits": ["A","C","O","P"] },
    { "name": "Tywin", "surname": "Lannister", "alive": false, "traits": ["O","M","H","F"] },
    { "name": "Davos", "surname": "Seaworth", "alive": true, "age": 49, "traits": ["C","K","P","F"] },
    { "name": "Samwell", "surname": "Tarly", "alive": true, "age": 17, "traits": ["C","L","I"] },
    { "name": "Stannis", "surname": "Baratheon", "alive": false, "traits": ["H","O","P","M"] },
    { "name": "Melisandre", "alive": true, "traits": ["G","E","H"] },
    { "name": "Margaery", "surname": "Tyrell", "alive": false, "traits": ["M","D","B"] },
    { "name": "Jeor", "surname": "Mormont", "alive": false, "traits": ["C","H","M","P"] },
    { "name": "Bronn", "alive": true, "traits": ["K","E","C"] },
    { "name": "Varys", "alive": true, "traits": ["M","F","N","E"] },
    { "name": "Shae", "alive": false, "traits": ["M","D","G"] },
    { "name": "Talisa", "surname": "Maegyr", "alive": false, "traits": ["D","C","B"] },
    { "name": "Gendry", "alive": false, "traits": ["K","C","A"] },
    { "name": "Ygritte", "alive": false, "traits": ["A","P","K"] },
    { "name": "Tormund", "surname": "Giantsbane", "alive": true, "traits": ["C","P","A","I"] },
    { "name": "Gilly", "alive": true, "traits": ["L","J"] },
    { "name": "Brienne", "surname": "Tarth", "alive": true, "age": 32, "traits": ["P","C","A","K"] },
    { "name": "Ramsay", "surname": "Bolton", "alive": true, "traits": ["E","O","G","A"] },
    { "name": "Ellaria", "surname": "Sand", "alive": true, "traits": ["P","O","A","E"] },
    { "name": "Daario", "surname": "Naharis", "alive": true, "traits": ["K","P","A"] },
    { "name": "Missandei", "alive": true, "traits": ["D","L","C","M"] },
    { "name": "Tommen", "surname": "Baratheon", "alive": true, "traits": ["I","L","B"] },
    { "name": "Jaqen", "surname": "H'ghar", "alive": true, "traits": ["H","F","K"] },
    { "name": "Roose", "surname": "Bolton", "alive": true, "traits": ["H","E","F","A"] },
    { "name": "The High Sparrow", "alive": true, "traits": ["H","M","F","O"] }
]

FOR d IN data
    INSERT d INTO Characters
複製代碼

語法:

LET variableName = valueExpression

LET關鍵字定義了同名稱的變量數據和對象值的數列,格式爲[ {...}, {...}, ... ]

FOR variableName IN expression

用於迭代數據數組的每一個元素 。在每一個循環中,將一個元素分配給變量d。而後在INSERT語句中使用此變量。至關於下面的格式:

INSERT {
    "name": "Robert",
    "surname": "Baratheon",
    "alive": false,
    "traits": ["A","H","C"]
} INTO Characters

INSERT {
    "name": "Jaime",
    "surname": "Lannister",
    "alive": true,
    "age": 36,
    "traits": ["A","F","B"]
} INTO Characters

...
複製代碼

檢索

檢索集合中的全部文檔:

FOR c IN Characters
    RETURN c
複製代碼

語法:

FOR variableName IN collectionName

對於集合中的每一個文檔,依次分配給變量c,而後根據循環體返回該文檔。

選取其中一個文檔以下:

{
    "_key": "2861650",
    "_id": "Characters/2861650",
    "_rev": "_V1bzsXa---",
    "name": "Ned",
    "surname": "Stark",
    "alive": true,
    "age": 41,
    "traits": ["A","H","C","N","P"]
  },
複製代碼

該文檔包含咱們存儲的四個屬性,以及數據庫系統添加的另外三個屬性:

  • _key:文檔鍵,用戶能夠在建立文檔時提供文檔鍵,也能夠自動分配惟一值,不能改變,只讀

  • _id:集合名/文檔鍵,只讀

  • _rev:系統管理的修訂版ID,只讀

檢索特定文檔:

RETURN DOCUMENT("Characters", "2861650") // --- or --- RETURN DOCUMENT("Characters/2861650") 複製代碼

返回:

[
  {
    "_key": "2861650",
    "_id": "Characters/2861650",
    "_rev": "_V1bzsXa---",
    "name": "Ned",
    "surname": "Stark",
    "alive": true,
    "age": 41,
    "traits": ["A","H","C","N","P"]
  }
] 
複製代碼

語法:

DOCUMENT()

使用_key或_id檢索特定文檔,該函數還容許一次獲取多個文檔

RETURN DOCUMENT("Characters", ["2861650", "2861653"]) // --- or --- RETURN DOCUMENT(["Characters/2861650", "Characters/2861653"]) 複製代碼

更新文檔:

修改現有文件:

UPDATE "2861650" WITH { alive: false } IN Characters
語法:
UPDATE documentKey WITH object IN collectionName

複製代碼

用列出的屬性更新指定的文檔(若是它們不存在則添加它們),但保持其他不變。要替換整個文檔內容,則要使用REPLACE函數:

REPLACE "2861650" WITH {
    name: "Ned",
    surname: "Stark",
    alive: false,
    age: 41,
    traits: ["A","H","C","N","P"]
} IN Characters 
複製代碼

該函數也適用於循環,例如爲全部文檔添加新屬性:

FOR c IN Characters
    UPDATE c WITH { season: 1 } IN Characters

複製代碼

刪除文件:

語法:

REMOVE _key IN Collectiosname

要從集合中徹底刪除文檔,須要執行REMOVE操做。它的工做方式與其餘修改操做相似,但沒有WITH子句:

REMOVE "2861650" IN Characters 

複製代碼

3、匹配文件

語法:

FILTER

查找知足比_key相等更復雜的條件的文檔,可以爲要匹配的文檔制定任意條件。

等於條件:

FOR c IN Characters
    FILTER c.name == "Ned"
    RETURN c
複製代碼

過濾條件以下:「 字符文檔的屬性name必須等於字符串Ned 」。若是條件適用,則返回字符文檔。

範圍條件:

FOR c IN Characters
    FILTER c.age >= 13
    RETURN c.name

複製代碼

多種條件:

FOR c IN Characters
    FILTER c.age < 13
    FILTER c.age != null
    RETURN { name: c.name, age: c.age }

//or

FOR c IN Characters
    FILTER c.age < 13 AND c.age != null
    RETURN { name: c.name, age: c.age } 
複製代碼

替代條件:

FOR c IN Characters
    FILTER c.name == "Jon" OR c.name == "Joffrey"
    RETURN { name: c.name, surname: c.surname } 
複製代碼

4、排序和限制

限制語法:

LIMIT()

LIMIT後面跟着一個最大顯示數的數字,限制結果顯示行數。

FOR c IN Characters
    LIMIT 5
    RETURN c.name
複製代碼

還可使用LIMIT來跳過必定數量的記錄返回下一個n個文檔:

FOR c IN Characters
    LIMIT 2, 5
    RETURN c.name

複製代碼

排序語法:

SORT()

DESC降序來反轉排序順序

FOR c IN Characters
    SORT c.name DESC
    LIMIT 10
    RETURN c.name
複製代碼

多個字段排序

FOR c IN Characters
    FILTER c.surname
    SORT c.surname, c.name
    LIMIT 10
    RETURN {
        surname: c.surname,
        name: c.name
    }
複製代碼

此處FILTER的做用是僅保留surname爲非空記錄

5、組合

語法: MERGE()

MERGE()的功能是將對象組合在一塊兒。由於使用了原始字符屬性{ traits: ... },因此後者被合併覆蓋。

FOR c IN Characters
    RETURN MERGE(c, { traits: DOCUMENT("Traits", c.traits)[*].en } )
複製代碼

6、圖操做

建立圖:

語法:

INSERT { _from: _id(A), _to: _id(B) } INTO ChildOf

實例: 首先,建立一個新的集合,並確保將集合類型更改成Edge。

ArangoDB

而後,經過查詢多個集合的數據,將結果存入邊集合中

LET data = [                                                        //關係數據
    {
        "parent": { "name": "Ned", "surname": "Stark" },
        "child": { "name": "Robb", "surname": "Stark" }
    }, {
        "parent": { "name": "Ned", "surname": "Stark" },
        "child": { "name": "Sansa", "surname": "Stark" }
    }, {
        "parent": { "name": "Ned", "surname": "Stark" },
        "child": { "name": "Arya", "surname": "Stark" }
    }, {
        "parent": { "name": "Ned", "surname": "Stark" },
        "child": { "name": "Bran", "surname": "Stark" }
    }, {
        "parent": { "name": "Catelyn", "surname": "Stark" },
        "child": { "name": "Robb", "surname": "Stark" }
    }, {
        "parent": { "name": "Catelyn", "surname": "Stark" },
        "child": { "name": "Sansa", "surname": "Stark" }
    }, {
        "parent": { "name": "Catelyn", "surname": "Stark" },
        "child": { "name": "Arya", "surname": "Stark" }
    }, {
        "parent": { "name": "Catelyn", "surname": "Stark" },
        "child": { "name": "Bran", "surname": "Stark" }
    }, {
        "parent": { "name": "Ned", "surname": "Stark" },
        "child": { "name": "Jon", "surname": "Snow" }
    }, {
        "parent": { "name": "Tywin", "surname": "Lannister" },
        "child": { "name": "Jaime", "surname": "Lannister" }
    }, {
        "parent": { "name": "Tywin", "surname": "Lannister" },
        "child": { "name": "Cersei", "surname": "Lannister" }
    }, {
        "parent": { "name": "Tywin", "surname": "Lannister" },
        "child": { "name": "Tyrion", "surname": "Lannister" }
    }, {
        "parent": { "name": "Cersei", "surname": "Lannister" },
        "child": { "name": "Joffrey", "surname": "Baratheon" }
    }, {
        "parent": { "name": "Jaime", "surname": "Lannister" },
        "child": { "name": "Joffrey", "surname": "Baratheon" }
    }
]

FOR rel in data
    LET parentId = FIRST(                                    //FIRST()提取第一個元素
        FOR c IN Characters
            FILTER c.name == rel.parent.name                    //篩選條件
            FILTER c.surname == rel.parent.surname
            LIMIT 1
            RETURN c._id                                                 //返回_id
    )
    LET childId = FIRST(
        FOR c IN Characters
            FILTER c.name == rel.child.name
            FILTER c.surname == rel.child.surname
            LIMIT 1
            RETURN c._id
    )
    FILTER parentId != null AND childId != null                        //剔除_id都爲空的記錄
    INSERT { _from: childId, _to: parentId } INTO ChildOf       //將數據插入邊集合
    RETURN NEW                                                                   //返回數據 
複製代碼

也能夠直接建立邊數據:

INSERT { _from: "Characters/robb", _to: "Characters/ned" } INTO ChildOf
複製代碼

遍歷圖:

語法:

FOR v IN 1..1 OUTBOUND _id ChildOf

    RETURN v.name

其中1..1爲遍歷深度
複製代碼

實例:

FOR c IN Characters
    FILTER c.name == "Bran"
    FOR v IN 1..1 OUTBOUND c ChildOf
        RETURN v.name
複製代碼

返回

[
  "Ned",
  "Catelyn"
]
複製代碼

遍歷的狀況以下圖:

ArangoDB

如果反向遍歷,則須要使用到INBOUND關鍵字:

FOR c IN Characters
    FILTER c.name == "Tywin"
    FOR v IN 2..2 INBOUND c ChildOf
        RETURN DISTINCT v.name
輸出:

[
  "Joffrey"
] 

複製代碼

遍歷狀況以下:

ArangoDB

須要注意的是,「1..1」限制了遍歷深度爲1,「2..2」限制了遍歷深度爲2,而"1..2"限制遍歷深度既能夠爲1也能夠爲2。

7、地理空間查詢

地點數據

建立地點集合:

ArangoDB

錄入地點數據:

LET places = [
    { "name": "Dragonstone", "coordinate": [ 55.167801, -6.815096 ] },
    { "name": "King's Landing", "coordinate": [ 42.639752, 18.110189 ] },
    { "name": "The Red Keep", "coordinate": [ 35.896447, 14.446442 ] },
    { "name": "Yunkai", "coordinate": [ 31.046642, -7.129532 ] },
    { "name": "Astapor", "coordinate": [ 31.50974, -9.774249 ] },
    { "name": "Winterfell", "coordinate": [ 54.368321, -5.581312 ] },
    { "name": "Vaes Dothrak", "coordinate": [ 54.16776, -6.096125 ] },
    { "name": "Beyond the wall", "coordinate": [ 64.265473, -21.094093 ] }
]

FOR place IN places
    INSERT place INTO Locations
複製代碼

設置地理空間索引:

在COLLECTIONS界面,添加新的Indexes,設置爲coordinate字段:

ArangoDB

ArangoDB

查找附近的位置

語法:

NEAR()

找到最接近的座標參考點

FOR loc IN NEAR(Locations, 53.35, -6.26, 3) RETURN {
        name: loc.name,
        latitude: loc.coordinate[0],
        longitude: loc.coordinate[1]
    }
複製代碼

輸出:

[
  {
    "name": "Vaes Dothrak",
    "latitude": 54.16776,
    "longitude": -6.096125
  },
  {
    "name": "Winterfell",
    "latitude": 54.368321,
    "longitude": -5.581312
  },
  {
    "name": "Dragonstone",
    "latitude": 55.167801,
    "longitude": -6.815096
  }
]
複製代碼

查找半徑內的位置

語法:

WITHIN()

從參考點搜索給定半徑內的位置

FOR loc IN WITHIN(Locations, 53.35, -6.26, 200 * 1000) RETURN {
        name: loc.name,
        latitude: loc.coordinate[0],
        longitude: loc.coordinate[1]
    }
複製代碼

輸出

[
  {
    "name": "Vaes Dothrak",
    "latitude": 54.16776,
    "longitude": -6.096125
  },
  {
    "name": "Winterfell",
    "latitude": 54.368321,
    "longitude": -5.581312
  }
]
複製代碼

按距離查找位置:

語法:

NEAR()或WITHIN()

經過添加一個可選的第五個參數返回到參考點的距離。必須是一個字符串:

FOR loc IN NEAR(Locations, 53.35, -6.26, 3, "distance") RETURN {
        name: loc.name,
        latitude: loc.coordinate[0],
        longitude: loc.coordinate[1],
        distance: loc.distance / 1000
    }
複製代碼

輸出:

[
  {
    "name": "Vaes Dothrak",
    "latitude": 54.16776,
    "longitude": -6.096125,
    "distance": 91.56658640314431
  },
  {
    "name": "Winterfell",
    "latitude": 54.368321,
    "longitude": -5.581312,
    "distance": 121.66399816395028
  },
  {
    "name": "Dragonstone",
    "latitude": 55.167801,
    "longitude": -6.815096,
    "distance": 205.31879386198324
  }
]
複製代碼

使用AQL遇到的問題:

問題1:如何對查詢結果進行計數並返回?

  • 解決方法:
RETURN COUNT(FOR v IN visitors FILTER v.ip == "127.0.0.1" RETURN 1) 複製代碼
相關文章
相關標籤/搜索