View Source Getting Started
This is an introduction on how to use the ArangoXEcto package, an ArangoDB adapter for Ecto. This adapts the various facets of the Ecto implementation to work for graph databases.
This guide will cover the basics of using ArangoXEcto, including creating, reading, updating and deleting records.
Note
You must already have an ArangoDB database setup
Adding ArangoXEcto to your project
Add the following line to your mix dependencies to get started.
{:arangox_ecto, "~> 2.0"}
To install these dependencies, we will run this command:
mix deps.get
This will also install the Arangox
dependency which is used for the
communication with the Arango database.
To connect to the database you need to specify the config values like so:
config :my_app, MyApp.Repo,
database: "my_db",
endpoints: "http://1.2.3.4:8529",
username: "root",
password: "root",
Only database
and endpoints
are required but there are other available
options can be found in the Arangox docs.
The database should be setup using the following.
mix ecto.create
Static or Dynamic
In addition to default config variables, the static
boolean config option can
be passed to force disable use of migrations. By default the value is true
and hence the by default it is in static mode and migrations are required.
If in dynamic mode collections that don't exist will be created on insert and
on query no error will be raised. If set to true
(default), any collections
that do not exist on insert or query will result in an error being raised.
Whether dynamic or static is chosen depends on the database design of the
project. For a production setup where lots of control is required, it is
recommended to have static
set to true
, which is the default.
Why even have dynamic mode?
Dynamic mode can be easier for development and testing (especially when you don't know what the database structure will look like) then after that point static mode can be turned on for production.
Repo Setup
To use the adapter in your repo, make sure your repo uses the ArangoXEcto.Adapter
module for the adapter.
defmodule MyApp.Repo do
use Ecto.Repo,
otp_app: :my_app,
adapter: ArangoXEcto.Adapter
end
Schema Setup
Since ArangoDB uses a slightly different id system, your schema must use the
ArangoXEcto.Schema
instead of Ecto.Schema
.
defmodule MyApp.Accounts.User do
use ArangoXEcto.Schema
import Ecto.Changeset
schema "users" do
field :first_name, :string
field :last_name, :string
timestamps()
end
@doc false
def changeset(app, attrs) do
app
|> cast(attrs, [:first_name, :last_name])
|> validate_required([:first_name, :last_name])
end
end
Dynamic Mode options and indexes
The ArangoXEcto.Schema.options/1
and ArangoXEcto.Schema.indexes/1
options
can be optionally called to set options and indexes to be created in dynamic
mode. These options will have no effect in static mode.
For example, if you wanted to use a UUID as the key type and create an index on the email the following can be used.
defmodule MyApp.Accounts.User do
use ArangoXEcto.Schema
import Ecto.Changeset
options [
keyOptions: %{type: :uuid}
]
indexes [
[fields: [:email]]
]
schema "users" do
field :email, :string
timestamps()
end
@doc false
def changeset(app, attrs) do
app
|> cast(attrs, [:first_name, :last_name])
|> validate_required([:first_name, :last_name])
end
end
Please refer to the Schema documentation for more information on the available options.
Migrations
Note
Using migrations is only required in static mode (the default) If in dynamic mode, the adapter will automatically create collections if they don't already exist.
Refer to ArangoXEcto.Migration for more information on usage.
defmodule MyApp.Repo.Migrations.CreateUsers do
use ArangoXEcto.Migration
def change do
create collection(:users) do
add :first_name, :string, comment: "first_name column"
add :last_name, :string
timestamps()
end
create index(:users, [:email])
end
end
Raw AQL queries
A lot of the time it is far more efficient to just run a raw AQL query, there's a function for that.
ArangoXEcto.aql_query(
Repo,
"FOR var in users FILTER var.first_name == @fname AND var.last_name == @lname RETURN var",
fname: "John",
lname: "Smith"
)
This query will return a result such as:
{:ok,
[
%{
"_id" => "users/12345",
"_key" => "12345",
"_rev" => "_bHZ8PAK---",
"first_name" => "John",
"last_name" => "Smith"
}
]}
This is awesome functionality, but a lot of the time we will want to resemble a
specific struct. This is actually quite easy with the help of the
ArangoXEcto.load/2
function. The same query above could be extended to also
convert the output:
ArangoXEcto.aql_query(
Repo,
"FOR var in users FILTER var.first_name == @fname AND var.last_name == @lname RETURN var",
fname: "John",
lname: "Smith"
)
|> case do
{:ok, results} ->
ArangoXEcto.load(results, User)
{:error, _reason} -> []
end
This will return something like:
[
%User{
id: "12345",
first_name: "John",
last_name: "Smith"
}
]
This is clearly a much better representation of the result and can be used in further Ecto methods.
Graph relations
You can find out how to write graph relations in the Graphing Guide
More information
To learn about using the schema functions for representing graph relationships and examples, read the docs at ArangoXEcto.Schema.
To read more about Edge Schemas and how to extend edge schemas to add additional fields, read the docs on ArangoXEcto.Edge.
To learn how to use the helper functions (as well as other useful methods) check out the full documentation.
For more examples and full documentation, please refer to the Documentation.