ArangoDB の Geo Indexes などを試した

こんにちは。
[ArangoDB](https://www.arangodb.com/key-features/) を初めて使ってみました。MongoDB に少し似ているようです。 [Key Features](https://github.com/arangodb/arangodb/blob/devel/README.md) を拾い読みすると

* Multi-Model: Documents, graphs and key-value pairs
* Joins
* Transactions (ACID)
* これらを AQL query で書ける
* 他に、Foxx (JavaScript framework) ...

自分でも、[Geo Indexes](https://docs.arangodb.com/IndexHandling/Geo.html) [^1] を試したり、Go で書いたプログラムを動かしてみました（[aranGO] (https://github.com/diegogub/aranGO) を利用）。最初は arangosh でアクセスすると、

```
$ arangosh
 :
 :

arangosh [_system]> db._listDatabases()
[ 
  "_system" 
]

arangosh [_system]> db._create("example");
[ArangoCollection 33715651, "example" (type document, status loaded)]

arangosh [_system]> db._collections()
 :
 :

arangosh [_system]> db.example.toArray();
[ ]

arangosh [_system]> db.example.save({"Hello": "World"});
{ 
  "_id" : "example/35747267", 
  "_rev" : "35747267", 
  "_key" : "35747267" 
}

arangosh [_system]> db.example.save({"name": "John Doe", "age": 29, "coordinates": [0, 0]});
 :
 :

arangosh [_system]> db.example.save({"name": "Jane Smith", "age": 31, "coordinates": [0.0001, 0]});
 :
 :

arangosh [_system]> db.example.ensureIndex({type: "geo", fields: ["coordinates"], geoJson: true})
{ 
  "id" : "example/37582275", 
  "type" : "geo1", 
  "fields" : [ 
    "coordinates" 
  ], 
  "geoJson" : true, 
  "constraint" : false, 
  "unique" : false, 
  "ignoreNull" : true, 
  "sparse" : true, 
  "isNewlyCreated" : true, 
  "code" : 201 
}

arangosh [_system]> db.example.getIndexes()
 :
 :
```

Go で書いたプログラムを走らせると（[aranGO] (https://github.com/diegogub/aranGO) を利用）、

```
$ go run arango.go 
[ 0 map[age:29 name:John Doe coordinates:[0 0] distance:5.559746332227936 _id:example/36730307 _key:36730307 _rev:36730307] ]
{{example/36730307 36730307 36730307 false } John Doe 29 [] [0 0]}
[ 1 map[_key:36926915 _rev:36926915 age:31 name:Jane Smith coordinates:[0.0001 0] distance:5.559746332227937 _id:example/36926915] ]
{{example/36926915 36926915 36926915 false } Jane Smith 31 [] [0.0001 0]}

[ 0 map[_key:36926915 age:31 name:Jane Smith coordinates:[0.0001 0] _id:example/36926915 _rev:36926915] ]
{{example/36926915 36926915 36926915 false } Jane Smith 31 [] [0.0001 0]}
[ 1 map[_id:example/35747267 _rev:35747267 _key:35747267 Hello:World] ]
{{example/35747267 35747267 35747267 false }  0 [] []}
[ 2 map[_id:example/36730307 _rev:36730307 _key:36730307 age:29 name:John Doe coordinates:[0 0]] ]
{{example/36730307 36730307 36730307 false } John Doe 29 [] [0 0]}
[ 3 map[age:0 name:Tony coordinates:[0.002 0] _id:example/4735230735 _key:4735230735 _rev:4735230735] ]
{{example/4735230735 4735230735 4735230735 false } Tony 0 [] [0.002 0]}
$ 
```

```arango.go
package main

import (
    "fmt"
    "encoding/json"
    "github.com/diegogub/aranGO"
)

type DocTest struct {
    aranGO.Document
    Name        string     `json:"name"`
    Age         int        `json:"age"`
    Likes       []string   `json:"likes,omitempty"`
    Coordinates []float64  `json:"coordinates"`  // [lon, lat]
}

func main() {
    sess, err := aranGO.Connect("http://localhost:8529", "root", "", false) 
    if err != nil{
        panic(err)
    }
    db := sess.DB("_system")

    col := "example"
    if !db.ColExist(col){
        panic("collection not found: " + col)
    }
	
	circle := map[string]float64{"lon": 0.00005, "lat": 0, "radius": 100}
    q := fmt.Sprintf("FOR d in WITHIN(%s, %f, %f, %f, \"distance\") FILTER d.age > 0 RETURN d", col, circle["lat"], circle["lon"], circle["radius"])
	cur, _ := db.Execute(aranGO.NewQuery(q))
    fetchAll(cur)

	var x DocTest
	x.Key = "4735230735" // 指定しない場合は、DB が自動的に値を決めて付与する
	x.Name = "Tony"
	x.Coordinates = []float64{0.002, 0}
	err = db.Col(col).Save(&x)
	fmt.Println("")
	cur, _ = db.Col(col).All(0,100)
	fetchAll(cur)
}

func fetchAll(cur *aranGO.Cursor) {
    for cur.Index < len(cur.Result) {
		var doc DocTest
		r := cur.Result[cur.Index]
		fmt.Println("[", cur.Index, r, "]")
		b, err := json.Marshal(r)
		err = json.Unmarshal(b, &doc)
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(doc)
		}
		cur.Index++
    }
}
```

arangosh の起動画面は、

```
$ /usr/local/sbin/arangod &
 :
 :

$ arangosh

                                       _     
  __ _ _ __ __ _ _ __   __ _  ___  ___| |__  
 / _` | '__/ _` | '_ \ / _` |/ _ \/ __| '_ \ 
| (_| | | | (_| | | | | (_| | (_) \__ \ | | |
 \__,_|_|  \__,_|_| |_|\__, |\___/|___/_| |_|
                       |___/                 

Welcome to arangosh 2.6.0 [darwin]. Copyright (c) ArangoDB GmbH
Using Google V8 3.31.74.1 JavaScript engine, READLINE 0x0402.hex, ICU 54.1

Pretty printing values.
Connected to ArangoDB 'tcp://127.0.0.1:8529' version: 2.6.0 [standalone], database: '_system', username: 'root'

Type 'tutorial' for a tutorial or 'help' to see common examples
arangosh [_system]>
```

[^1]: ArangoDB の地理座標系は左手系です。一部に限って```geojson=true```と設定すると右手系へ切り替えられます。