Oihana PHP Arango

operations

Table of Contents

Functions

aqlAsc()  : string
Builds an ascending AQL `SORT` expression for the given attribute key.
aqlCollect()  : string
Builds an AQL `COLLECT` clause for grouping, aggregation, and counting.
aqlCollectReturn()  : string
Builds the `RETURN` clause that follows an AQL `COLLECT` produced by {@see aqlCollect()}.
aqlDesc()  : string
Builds an descending AQL `SORT` expression for the given attribute key.
aqlFilter()  : string|null
Builds an AQL `FILTER` clause from one or more logical conditions.
aqlFor()  : string
Builds an ArangoDB AQL `FOR` clause, optionally including `SEARCH` and `OPTIONS` segments.
aqlInsert()  : string
Builds an AQL `INSERT` statement.
aqlLet()  : string
The LET operation defines a variable within an AQL query, which can then be used in subsequent expressions.
aqlLimit()  : string
Provides helpers to build AQL `LIMIT` clauses for ArangoDB queries, supporting **offsets**, **parameter binding**, and **dynamic query generation**.
aqlOptions()  : string
Builds the AQL `OPTIONS` clause from the provided options.
aqlPrune()  : string|null
Builds an AQL `PRUNE` clause from one or more logical conditions.
aqlRemove()  : string
Remove one or multiple documents from a collection using an AQL `REMOVE` operation.
aqlReplace()  : string
The REPLACE statement replaces an existing document with a new one, removing any attributes that are not explicitly set in the provided `doc` while preserving immutable system attributes (`_id`, `_key`, `_rev`).
aqlRepsert()  : string
Prepare a REPSERT query to replace an existing document or insert a new one if it does not exist.
aqlReturn()  : string
Builds an AQL `RETURN` clause from a given expression.
aqlScoredSearch()  : string
Builds a complete, relevance-ranked AQL search query over an ArangoSearch View.
aqlSearch()  : string
Builds an AQL `SEARCH` clause for a query, with optional Analyzer wrapping and an optional `OPTIONS` object.
aqlSort()  : string
Builds an AQL `SORT` clause from a string or an array of sort expressions.
aqlTraversal()  : string
Builds a full **AQL traversal clause** for ArangoDB queries.
aqlTraversalRange()  : string
Builds an AQL traversal range clause (e.g., `1..1`, `1..5`, `..2`, `3..`).
aqlUpdate()  : string
Partially modifies a document with the given attributes, by adding new and updating existing attributes.
aqlUpsert()  : string
Prepare the query to update an existing document, or creates a new document if it does not exist.
aqlVectorSearch()  : string
Builds a complete AQL approximate nearest-neighbour (ANN) query over a vector index.
aqlWindow()  : string
Builds an AQL `WINDOW` clause for sliding-window aggregation (running totals, rolling averages, and other statistical properties over related rows).
aqlWindowBounds()  : string
Serializes the `{ preceding: …, following: … }` bounds object of a `WINDOW` clause.
aqlWith()  : string
Generates an AQL `WITH` clause for one or more collections.

Functions

aqlAsc()

Builds an ascending AQL `SORT` expression for the given attribute key.

aqlAsc(string $key[, string|null $prefix = null ]) : string

This helper simplifies the creation of SORT clauses by combining the provided key (and optional prefix) with the ASC order keyword.

The resulting string can be directly injected into an AQL statement or composed with other expressions (e.g., using aqlSort()).

Example: basic usage

echo aqlAsc('age');
// → "age ASC"

Example: with prefix

echo aqlAsc('name', 'u');
// → "u.name ASC"

Example: combined in a SORT clause

echo 'SORT ' . aqlAsc('score', 'player');
// → "SORT player.score ASC"
Parameters
$key : string

The attribute name to sort by (e.g., 'age', 'createdAt', 'score').

$prefix : string|null = null

Optional variable or collection prefix (e.g., 'u' for "u.age").

Tags
see
aqlDesc()

For descending order.

https://docs.arangodb.com/stable/aql/fundamentals/sorting
since
1.0.0
author

Marc Alcaraz

Return values
string

The formatted ascending sort expression, e.g. "doc.name ASC".

aqlCollect()

Builds an AQL `COLLECT` clause for grouping, aggregation, and counting.

aqlCollect([array<string|int, mixed> $init = [] ]) : string

Supported $init keys

Key Type Description
AQL::ASSIGN array Grouping variables, e.g., ['group' => 'doc.type'].
AQL::AGGREGATE array Aggregation expressions, e.g., ['total' => 'SUM(doc.value)'].
AQL::INTO string Variable name to collect documents into (e.g., 'groupDocs').
AQL::PROJECTION string Projection expression for the INTO clause (e.g., 'doc.name').
AQL::KEEP array An array of variable names to keep (e.g., ['var1', 'var2']).
AQL::WITH_COUNT string Variable name for the count (e.g., AQL::LENGTH).
AQL::OPTIONS array COLLECT options (e.g., ['method' => 'sorted']).

Note: AQL::AGGREGATE and AQL::WITH_COUNT are mutually exclusive in AQL. When both are supplied, AGGREGATE takes precedence and WITH COUNT INTO is dropped. To count alongside other aggregates, express the count as an aggregate (e.g., ['n' => 'LENGTH(1)']).

Examples

Simple Count (for countVertices):

echo aqlCollect([ AQL::WITH_COUNT => AQL::LENGTH ]);
// COLLECT WITH COUNT INTO length

Grouping and Aggregating:

echo aqlCollect
([
    AQL::ASSIGN    => ['type' => 'doc.type'],
    AQL::AGGREGATE => ['count' => 'LENGTH(1)']
]);
// COLLECT type = doc.type AGGREGATE count = LENGTH(1)

Grouping with INTO:

echo aqlCollect
([
    AQL::ASSIGN     => ['type' => 'doc.type'],
    AQL::INTO       => 'items',
    AQL::PROJECTION => '{ name: doc.name, age: doc.age }'
]);
// COLLECT type = doc.type INTO items = { name: doc.name, age: doc.age }
Parameters
$init : array<string|int, mixed> = []

Associative array of collect options.

Tags
throws
ReflectionException
since
1.0.0
author

Marc Alcaraz

Return values
string

The compiled AQL COLLECT clause, or an empty string if invalid.

aqlCollectReturn()

Builds the `RETURN` clause that follows an AQL `COLLECT` produced by {@see aqlCollect()}.

aqlCollectReturn([array<string|int, mixed> $spec = [] ][, string|null $explicit = null ]) : string

After a COLLECT, the iteration variable (e.g. doc) is out of scope: only the grouping variables, the aggregate variables and the optional WITH COUNT variable remain usable. This helper derives a valid projection from the very same $spec given to aqlCollect(), so the two always stay in sync.

Behaviour

  • An explicit, non-empty $explicit expression always wins (RETURN <expr>).
  • Otherwise the projection is derived from the spec:
    • grouping keys (array_keys(AQL::ASSIGN)) + aggregate keys (array_keys(AQL::AGGREGATE)),
    • plus the AQL::WITH_COUNT variable when present.
  • AQL::AGGREGATE and AQL::WITH_COUNT are mutually exclusive (mirrors aqlCollect()): when an aggregate is present the count variable is ignored.
  • A pure count (no grouping, no aggregate, only WITH_COUNT) returns the scalar count (RETURN length), not an object.
  • When nothing can be projected, an empty string is returned.

AQL::INTO collected documents are intentionally NOT auto-projected (they may be huge); pass an $explicit projection to expose them.

Examples

echo aqlCollectReturn([ AQL::ASSIGN => ['status' => 'doc.status'] ]);
// RETURN { status }

echo aqlCollectReturn([ AQL::ASSIGN => ['category' => 'doc.category'], AQL::WITH_COUNT => 'count' ]);
// RETURN { category, count }

echo aqlCollectReturn([ AQL::WITH_COUNT => 'length' ]);
// RETURN length

echo aqlCollectReturn([ AQL::ASSIGN => ['y' => 'DATE_YEAR(doc.created)'] ], '{ year: y }');
// RETURN { year: y }
Parameters
$spec : array<string|int, mixed> = []

The same associative spec passed to aqlCollect().

$explicit : string|null = null

An explicit RETURN expression overriding the derivation.

Tags
throws
UnsupportedOperationException
since
1.0.0
author

Marc Alcaraz

Return values
string

The compiled AQL RETURN clause, or an empty string when nothing to project.

aqlDesc()

Builds an descending AQL `SORT` expression for the given attribute key.

aqlDesc(string $key[, string|null $prefix = null ]) : string

This helper simplifies the creation of SORT clauses by combining the provided key (and optional prefix) with the DESC order keyword.

The resulting string can be directly injected into an AQL statement or composed with other expressions (e.g., using aqlSort()).

Example: basic usage

echo aqlDesc('age');
// → "age DESC"

Example: with prefix

echo aqlDesc('name', 'u');
// → "u.name DESC"

Example: combined in a SORT clause

echo 'SORT ' . aqlDesc('score', 'player');
// → "SORT player.score DESC"
Parameters
$key : string

The attribute name to sort by (e.g., 'age', 'createdAt', 'score').

$prefix : string|null = null

Optional variable or collection prefix (e.g., 'u' for "u.age").

Tags
see
aqlAsc()

For ascending order.

https://docs.arangodb.com/stable/aql/fundamentals/sorting
since
1.0.0
author

Marc Alcaraz

Return values
string

The formatted descending sort expression, e.g. "doc.name DESC".

aqlFilter()

Builds an AQL `FILTER` clause from one or more logical conditions.

aqlFilter([string|array<string|int, mixed>|null $conditions = null ][, string $logicalOperator = Logic::AND ][, bool $useParentheses = false ]) : string|null

The FILTER operation restricts the results to elements that match arbitrary logical conditions.

Syntax:

FILTER expression

The expression must evaluate to either true or false.

Example:

use function oihana\arango\db\operations\aqlFilter;

echo aqlFilter( 'user.age > 18' ) . PHP_EOL;
// FILTER user.age > 18

echo aqlFilter( [ 'user.active == true', 'user.age >= 18' ] ) . PHP_EOL;
// FILTER user.active == true && user.age >= 18

echo aqlFilter( [ 'x > 5', 'y < 10' ], '||' ) . PHP_EOL;
// FILTER x > 5 || y < 10

echo aqlFilter(); // null
Parameters
$conditions : string|array<string|int, mixed>|null = null

The expression(s) to evaluate in the FILTER operation.

$logicalOperator : string = Logic::AND

The logical operator used to join conditions if $conditions is an array (default &&).

$useParentheses : bool = false

Whether to wrap the result in parentheses.

Tags
see
https://docs.arangodb.com/stable/aql/high-level-operations/filter
since
1.0.0

author Marc Alcaraz

Return values
string|null

The compiled AQL FILTER clause, or null if no valid condition was provided.

aqlFor()

Builds an ArangoDB AQL `FOR` clause, optionally including `SEARCH` and `OPTIONS` segments.

aqlFor([array<string|int, mixed> $init = [] ]) : string

The generated query follows this canonical form:

FOR <variableName> IN <expression> [SEARCH <searchExpression>] [OPTIONS { ... }]

This function simplifies the construction of AQL loops by automatically compiling the parts (IN, SEARCH, OPTIONS) using helper functions such as aqlSearch() and aqlOptions().

Supported $init keys

Key Type Description
AQL::DOC_REF `string null`
AQL::IN `string null`
AQL::SEARCH `string null`
AQL::OPTIONS `array object

Example: basic usage

echo aqlFor([
    AQL::DOC_REF => 'doc',
    AQL::IN      => 'users'
]);
// → "FOR doc IN users"

Example: with SEARCH and OPTIONS

echo aqlFor
([
    AQL::DOC_REF  => 'u',
    AQL::IN       => 'searchUsers',
    AQL::SEARCH   => 'u.active == true',
    AQL::OPTIONS  =>
    [
        'indexHint'       => 'byActive',
        'forceIndexHint'  => true,
        'disableIndex'    => false,
        'useCache'        => true,
        'lookahead'       => 5
    ]
]);
// → "FOR u IN searchUsers SEARCH u.active == true OPTIONS {\"indexHint\":\"byActive\",\"forceIndexHint\":true,\"disableIndex\":false,\"useCache\":true,\"lookahead\":5}"

Example: using a ForOptions schema object

use oihana\arango\db\options\ForOptions;

$opts = new ForOptions([
    'useCache'  => false,
    'lookahead' => 3
]);

echo aqlFor
`([
    AQL::DOC_REF => 'd',
    AQL::IN      => 'documents',
    AQL::OPTIONS => $opts
]);
// → "FOR d IN documents OPTIONS {\"useCache\":false,\"lookahead\":3}"
Parameters
$init : array<string|int, mixed> = []

An associative array defining the FOR clause elements. Example structure:

[
    AQL::DOC_REF => 'doc',
    AQL::IN      => 'users',
    AQL::SEARCH  => 'doc.age > 30',
    AQL::OPTIONS => [ 'useCache' => true ]
]
Tags
throws
ReflectionException

If hydration of options into ForOptions fails.

see
https://docs.arangodb.com/stable/aql/high-level-operations/for
aqlSearch()
aqlOptions()
since
1.0.0
author

Marc Alcaraz

Return values
string

The complete AQL FOR clause, or an empty string if no valid input is provided.

aqlInsert()

Builds an AQL `INSERT` statement.

aqlInsert([array<string|int, mixed> $init = [] ][, array<string|int, mixed>|null &$binds = null ][, string|null $queryID = null ]) : string

This method dynamically constructs an ArangoDB AQL query of the form:

INSERT {document} INTO collection OPTIONS {...} RETURN NEW

It supports binding collection names, attaching additional insert options, and optionally returning the newly inserted document.

The $init array may contain:

  • AQL::DOCUMENT (array|object|string) — The document to insert.
  • AQL::COLLECTION (string) — The target collection name.
  • AQL::BIND_COLLECTION (bool) — Whether to bind the collection as a variable.
  • AQL::QUERY_ID (string) — An optional query identifier to prepend the default name of the bind collection variable.
  • AQL::RAW_VALUES (array) — Keys in the document whose values should be treated as raw AQL expressions.
  • AQL::USE_SPACE (bool) — Whether to add spaces around braces and commas for readability.
Parameters
$init : array<string|int, mixed> = []

An associative array containing the insert parameters.

$binds : array<string|int, mixed>|null = null

A reference array to hold bind variables for the query.

$queryID : string|null = null
Tags
throws
BindException

If binding a collection or variable fails.

ReflectionException

If there is an issue reflecting InsertOptions.

example

Example 1 — Insert a single document into a collection

echo aqlInsert
([
    AQL::DOCUMENT   => ['name' => 'Eka', 'age' => 47],
    AQL::COLLECTION => 'users'
]);
// INSERT {name:'Eka',age:47} INTO users OPTIONS } RETURN NEW

Insert a document with raw AQL expressions

echo aqlInsert
([
    AQL::DOCUMENT =>
    [
         '_key' => "CONCAT('test', i)",
         'name' => 'test',
         'active' => true
    ],
    AQL::RAW_VALUES => [ '_key' ] ,
    AQL::COLLECTION => 'items'
]);
// INSERT {_key:CONCAT('test', i),name:'test',active:true} INTO items OPTIONS } RETURN NEW

Insert a nested document with arrays

echo aqlInsert
([
    AQL::DOC =>
    [
         'user' => ['name' => 'Eka', 'roles' => ['admin','editor']],
         'active' => true
    ],
    AQL::USE_SPACE => true,
    AQL::COLLECTION => 'users'
]);
// INSERT { user:{name:'Eka',roles:['admin','editor']}, active:true } INTO users OPTIONS } RETURN NEW
see
InsertOptions

Allows passing advanced options such as overwriteMode, waitForSync, etc.

https://docs.arangodb.com/stable/aql/high-level-operations/insert
since
1.0.0
author

Marc Alcaraz

Return values
string

The compiled AQL INSERT query string, ready to be executed.

aqlLet()

The LET operation defines a variable within an AQL query, which can then be used in subsequent expressions.

aqlLet(string $variableName, string $expression[, bool $useParentheses = false ][, bool $trim = false ]) : string

A variable defined with LET exists only for the scope of the query or subquery.

Syntax:

LET variableName = expression

Example usage:

$query = let('total', 'SUM(doc.amount)');
// LET total = SUM(doc.amount)

Another examples:

$query = let('userName', "CONCAT(user.firstName, ' ', user.lastName)");
// LET userName = CONCAT(user.firstName, ' ', user.lastName)
$query = let( 'surface', 'doc.width * doc.height' , true );
// LET surface = ( doc.width * doc.height )
Parameters
$variableName : string
$expression : string
$useParentheses : bool = false
$trim : bool = false
Tags
since
1.0.0
author

Marc Alcaraz

Return values
string

aqlLimit()

Provides helpers to build AQL `LIMIT` clauses for ArangoDB queries, supporting **offsets**, **parameter binding**, and **dynamic query generation**.

aqlLimit(int $limit[, int $offset = 0 ][, array<string|int, mixed>|null &$binds = null ]) : string

The LIMIT clause in ArangoDB is used to:

  • Restrict the number of results returned by a query.
  • Optionally skip a number of documents using an offset.
  • Use bind parameters instead of hardcoded values to improve performance and prevent query plan cache invalidation. AQL Syntax*
LIMIT <count>
LIMIT <offset>, <count>

Why use bind parameters for LIMIT/OFFSET?*

Using placeholders like @limit and @offset allows ArangoDB to reuse the same query execution plan instead of recompiling it each time. This is particularly efficient when paginating through large datasets.

Examples:

// Simple limit
echo aqlLimit(10);
// LIMIT 10

// Limit with offset
echo aqlLimit(10, 5);
// LIMIT 5, 10

// Limit with bound parameters
$binds = [];
echo aqlLimit(10, 5, $binds);
// LIMIT @offset, @limit
// $binds = [ 'limit' => 10 , 'offset' => 5 ]
Parameters
$limit : int

Maximum number of results to return. Must be > 0 to generate a clause.

$offset : int = 0

Number of results to skip before starting to return results (default 0).

$binds : array<string|int, mixed>|null = null

Optional reference to a binds array for parameterized queries.

Tags
throws
BindException

If parameter binding fails.

since
1.0.0
author

Marc Alcaraz

Return values
string

AQL LIMIT clause string, or empty string if $limit <= 0.

aqlOptions()

Builds the AQL `OPTIONS` clause from the provided options.

aqlOptions([array<string|int, mixed> $init = [] ][, string|null $schema = null ]) : string

If $schema is provided, the method attempts to hydrate the options array into an instance of the specified schema class, provided it exists.

Supported input types for $init[AQL::OPTIONS]:

  • Associative array → converted to JSON after cleaning.
  • Object implementing JsonSerializable → serialized via jsonSerialize().
  • Generic object → cast to array and encoded as JSON if associative.
  • Pre-encoded JSON string → used directly.

If the resulting options are valid, the method returns a properly formatted OPTIONS { ... } clause. Otherwise, it returns an empty string.

Parameters
$init : array<string|int, mixed> = []

Initial options array. If it contains the key AQL::OPTIONS, its value will be processed. If absent, the method returns an empty string.

$schema : string|null = null

Optional fully-qualified class name of a schema to hydrate options into.

Tags
throws
ReflectionException

If hydration fails due to reflection issues.

example

Basic usage with array:

options([AQL::OPTIONS => ["fullCount" => true]]) ; // → "OPTIONS {\"fullCount\":true}"

Usage with schema hydration:

options
(
    [ AQL::OPTIONS => ["fullCount" => true, "batchSize" => 500 ] ],
    QueryOptions::class
);
since
1.0.0
author

Marc Alcaraz

Return values
string

The generated AQL OPTIONS clause, or an empty string if no valid options are provided.

aqlPrune()

Builds an AQL `PRUNE` clause from one or more logical conditions.

aqlPrune([string|array<string|int, mixed>|null $conditions = null ][, string $logicalOperator = Logic::AND ]) : string|null

The PRUNE operation is used in graph traversals to stop traversing along the current path if the condition is met.

Syntax:

PRUNE expression

The expression must evaluate to either true or false.

Example:

use function oihana\arango\db\operations\aqlPrune;

echo aqlPrune( 'v.age > 40' ) . PHP_EOL;
// PRUNE v.age > 40

echo aqlPrune( [ 'e.type == "friend"', 'v.status == "inactive"' ], '||' ) . PHP_EOL;
// PRUNE e.type == "friend" || v.status == "inactive"

echo aqlPrune(); // null
Parameters
$conditions : string|array<string|int, mixed>|null = null

The expression(s) to evaluate in the FILTER operation.

$logicalOperator : string = Logic::AND

The logical operator used to join conditions if $conditions is an array (default &&).

Tags
see
https://docs.arangodb.com/3.10/aql/graphs/traversals/#pruning
since
1.0.0

author Marc Alcaraz

Return values
string|null

The compiled AQL PRUNE clause, or null if no valid condition was provided.

aqlRemove()

Remove one or multiple documents from a collection using an AQL `REMOVE` operation.

aqlRemove([array{collection?: ?string, expression?: ?string, key?: ?string, options?: ?array{exclusive?: bool, ignoreErrors?: bool, ignoreRevs?: bool, refillIndexCaches?: bool, waitForSync?: bool}} $init = [] ]) : string

This helper builds a valid AQL query string for removing documents based on either:

  • a custom key expression, or
  • a document key (_key) and an optional document prefix (defaults to doc).

AQL syntax:

REMOVE <keyExpression> IN <collection> [OPTIONS {...}]
Parameters
$init : array{collection?: ?string, expression?: ?string, key?: ?string, options?: ?array{exclusive?: bool, ignoreErrors?: bool, ignoreRevs?: bool, refillIndexCaches?: bool, waitForSync?: bool}} = []

Initial options array.

  • 'collection' : The name of the collection in which the document should be updated. By default, if the argument is null, use @@collection bindVars definition.
  • 'expression' : The key expression that contains the document identification. If the expression is null or an empty string, the 'key' and 'prefix' definitions are used.
  • 'key' : The unique identifier of the document to remove. By default _key -> REMOVE doc._key IN ...
  • 'options' : Build a RemoveOptions definition to inject at the end of the query.
  • 'prefix' : Optional The name of the document reference. By default doc -> REMOVE doc._key IN ...
Tags
throws
InvalidArgumentException

If the collection name is missing.

ReflectionException

If a reflection error occurs while building options.

UnsupportedOperationException

If the operation is not supported.

example

Example usage:

Basic removal by document key:

echo $this->remove([ 'collection' => 'users', 'key' => '_key' ]);
// "REMOVE {_key:doc._key} IN users"

Using a custom key expression:

echo $this->remove
([
    'collection' => 'products',
    'expression' => 'item._key'
]);
// "REMOVE item._key IN products"

With options

echo $this->remove
([
    'collection' => 'logs',
    'options'    =>
    [
        'ignoreErrors'      => true ,
        'waitForSync'       => false ,
        'refillIndexCaches' => true ,
    ]
]);
// "REMOVE {_key:doc._key} IN logs OPTIONS { ignoreErrors: true, waitForSync: false, refillIndexCaches: true }"
see
https://docs.arangodb.com/stable/aql/high-level-operations/remove
author

Marc Alcaraz

since
1.0.0
Return values
string

The compiled AQL REMOVE statement.

aqlReplace()

The REPLACE statement replaces an existing document with a new one, removing any attributes that are not explicitly set in the provided `doc` while preserving immutable system attributes (`_id`, `_key`, `_rev`).

aqlReplace([ReplaceOptions|null, with?: string|null} $init = [] ]) : string

Basic Syntax:*

REPLACE `document` IN `collection`
REPLACE `keyExpression` WITH `document` IN `collection`
Parameters
$init : ReplaceOptions|null, with?: string|null} = []

Initial options for the REPLACE statement, with the keys:

  • 'collection' : The name of the collection in which the document should be replaced.
  • 'doc' : An object and contain the attributes and values to replace.
  • 'options' : The default 'options' expression definition
  • 'rawValues' : array, keys whose values should be treated as raw AQL expressions - used with the 'with' option)
  • 'rawKeys' : array, keys which should be kept raw (their values are not wrapped or converted) - used with the 'with' option)
  • 'useSpace' : bool, add spaces around braces and after commas
  • 'with' : One or multiple collections for WITH clause -> WITH collection1 [, collection2 [, ... collectionN ] ]
Tags
throws
ReflectionException

If options serialization or internal reflection fails.

Examples**

// Replace a document by key
$this->replace
([
   'collection' => 'users',
   'doc'        => [ '_key' => 123 , 'name' => "John" ]
]);
// Produces: REPLACE {_key:"123",name: "John"} IN users

// Replace with additional collections and options
$this->replace
([
    'collection' => 'orders',
    'key'        => key( 'my_key' , 'doc' ) ,
    'with'       => [ 'status' => 'shipped' ] ,
    'options'    => [ 'ignoreRevs' => true ]
]);
// Produces: REPLACE doc.my_key WITH {'status':'shipped'} IN orders {"ignoreRevs":true}
see
https://docs.arangodb.com/stable/aql/high-level-operations/replace
ReplaceOptions
author

Marc Alcaraz

since
1.0.0
Return values
string

aqlRepsert()

Prepare a REPSERT query to replace an existing document or insert a new one if it does not exist.

aqlRepsert([array<string|int, mixed> $init = [] ]) : string
UPSERT [ searchExpression | FILTER filterExpression ]
INSERT insertExpression
REPLACE replaceExpression
IN collection

Options in $init:

  • collection: string|null, name of the collection.
  • filter: array|string|null, optional filter expression.
  • search: array|string|null, the search document.
  • insert: array|string|null, the document to insert if no match is found.
  • replace: array|string|null, the document to replace if a match is found.
  • options: array|QueryOptions|string|JsonSerializable|null, optional upsert options.
  • return: optional expression to define the RETURN clause. Default is Clause::NEW. You can also use Clause::WITH_STATUS to return both the document and the type of operation.
Parameters
$init : array<string|int, mixed> = []

Configuration options for the REPSERT query.

Tags
throws
ReflectionException
UnsupportedOperationException
example
$query = aqlRepsert
([
    'search'  => [['foo', 'bar']],
    'insert'  => [['foo', 'bar']],
    'replace' => [['foo', 'baz']],
]);
// Returns: "UPSERT {foo:'bar'} INSERT {foo:'bar'} REPLACE {foo:'baz'} IN @@collection RETURN NEW"
see
https://docs.arangodb.com/stable/aql/high-level-operations/upsert
since
1.0.0
author

Marc Alcaraz

Return values
string

The generated AQL UPSERT query.

aqlReturn()

Builds an AQL `RETURN` clause from a given expression.

aqlReturn(mixed $expression[, bool $distinct = false ]) : string

A RETURN operation is mandatory at the end of each AQL query block, otherwise the query result would be undefined. Using RETURN at the top level in data modification queries is optional.

Example:

use function oihana\arango\db\operations\aqlReturn;

echo aqlReturn( 'user.name' ) . PHP_EOL;
// RETURN user.name

echo aqlReturn( Clause::NEW ) . PHP_EOL;
// RETURN NEW

echo aqlReturn( 'user.email' , true ) . PHP_EOL;
// RETURN DISTINCT user.email
Parameters
$expression : mixed

The expression to evaluate (array or string).

$distinct : bool = false

Whether to add the DISTINCT keyword in the RETURN clause.

Tags
see
https://docs.arangodb.com/stable/aql/high-level-operations/return
since
1.0.0
author

Marc Alcaraz

Return values
string

The compiled AQL RETURN clause, or an empty string if expression is empty.

aqlScoredSearch()

Builds a complete, relevance-ranked AQL search query over an ArangoSearch View.

aqlScoredSearch(string $view, string|array<string|int, mixed> $search, int $limit[, string|null $analyzer = null ][, array<string|int, mixed>|object|string|null $options = null ][, string $scorer = SearchScorer::BM25 ][, float|null $k = null ][, float|null $b = null ][, bool|null $normalize = null ][, int $offset = 0 ][, string $docRef = 'doc' ][, string $scoreRef = 'score' ][, string|null $return = null ]) : string

The generated query follows the canonical scored-search form:

FOR <docRef> IN <view>
  SEARCH <expression> [OPTIONS { … }]
  LET <scoreRef> = BM25(<docRef>) | TFIDF(<docRef>)
  SORT <scoreRef> DESC
  LIMIT [<offset>,] <limit>
  RETURN <return>

Both scorers rank better matches with higher values, so the sort is always descending — there is no direction to get wrong. The score is bound to a LET variable ($scoreRef, default score) so a custom $return expression can expose it, e.g. 'MERGE(doc, { score: score })'.

The SEARCH segment reuses aqlFor() / aqlSearch(): the optional $analyzer wraps the expression in ANALYZER(expr, "name") and the optional $options becomes the SEARCH … OPTIONS { … } object (hydrated into SearchOptions).

The scorer functions require the indexed fields' Analyzers to have the "frequency" feature enabled (and "norm" for meaningful BM25 length normalization), otherwise the score is 0.

Example: phrase search ranked by BM25

use function oihana\arango\db\functions\search\phrase;
use function oihana\arango\db\operations\aqlScoredSearch;

$aql = aqlScoredSearch
(
    view     : 'placesView' ,
    search   : phrase( 'doc.name' , 'scierie' ) ,
    limit    : 20 ,
    analyzer : 'text_fr' ,
) ;
// FOR doc IN placesView SEARCH ANALYZER(PHRASE(doc.name,"scierie"),"text_fr")
//   LET score = BM25(doc) SORT score DESC LIMIT 20 RETURN doc

Example: TF-IDF, pagination, and the score in the output

$aql = aqlScoredSearch
(
    view      : 'articlesView' ,
    search    : 'doc.text IN TOKENS(@q, "text_en")' ,
    limit     : 10 ,
    offset    : 20 ,
    scorer    : SearchScorer::TFIDF ,
    normalize : true ,
    return    : 'MERGE(doc, { score: score })' ,
) ;
// FOR doc IN articlesView SEARCH doc.text IN TOKENS(@q, "text_en")
//   LET score = TFIDF(doc,true) SORT score DESC LIMIT 20, 10 RETURN MERGE(doc, { score: score })
Parameters
$view : string

The ArangoSearch View to query.

$search : string|array<string|int, mixed>

The SEARCH expression (kept raw; arrays are compiled like AQL::SEARCH).

$limit : int

The maximum number of matches to return (the LIMIT).

$analyzer : string|null = null

Optional Analyzer name wrapping the expression in ANALYZER(expr, "name").

$options : array<string|int, mixed>|object|string|null = null

Optional SEARCH … OPTIONS { … } object (see aqlSearch()).

$scorer : string = SearchScorer::BM25

The scoring algorithm: SearchScorer::BM25 (default) or SearchScorer::TFIDF.

$k : float|null = null

Optional BM25 term-frequency calibration (BM25 only).

$b : float|null = null

Optional BM25 text-length scaling (BM25 only).

$normalize : bool|null = null

Optional TF-IDF score normalization (TFIDF only).

$offset : int = 0

Optional number of matches to skip (pagination).

$docRef : string = 'doc'

The iteration variable name (default 'doc').

$scoreRef : string = 'score'

The LET score variable name (default 'score').

$return : string|null = null

Optional RETURN expression. Defaults to the iteration variable.

Tags
throws
BindException
ReflectionException

If the search options hydration fails.

see
https://docs.arangodb.com/stable/aql/functions/arangosearch/#scoring-functions
SearchScorer
aqlSearch()
bm25()
tfidf()
since
1.2.0
author

Marc Alcaraz

Return values
string

The complete AQL scored-search query.

aqlSearch()

Builds an AQL `SEARCH` clause for a query, with optional Analyzer wrapping and an optional `OPTIONS` object.

aqlSearch([array<string|int, mixed> $init = [] ]) : string

The SEARCH operation guarantees the use of View indexes for an efficient execution plan. Using FILTER on Views does not utilize indexes and filtering is done as a post-processing step.

$init keys:

  • AQL::SEARCH — the search expression. Without it everything else is ignored and an empty string is returned.
  • AQL::ANALYZER (optional) — an Analyzer name; the expression is wrapped in ANALYZER(expr, "name") via analyzer(), setting the Analyzer for the expression and its nested functions.
  • AQL::SEARCH_OPTIONS (optional) — the SEARCH … OPTIONS { … } object (collections, conditionOptimization, countApproximate, parallelism), accepted as an associative array (hydrated into SearchOptions, unknown keys dropped, null properties omitted), a SearchOptions instance, any JsonSerializable/plain object, or a pre-encoded JSON string — the same tolerance as aqlOptions().

Not to be confused with AQL::OPTIONS, the FOR-level options (indexHint, useCache, … — see ForOptions): a FOR over a collection takes AQL::OPTIONS, a SEARCH against a View takes AQL::SEARCH_OPTIONS. aqlFor() forwards its whole $init here, so all three keys work through it directly.

Example:

use oihana\arango\db\enums\AQL;
use oihana\arango\db\enums\ConditionOptimization;
use function oihana\arango\db\operations\aqlSearch;

echo aqlSearch([ AQL::SEARCH => 'PHRASE(doc.text, "search phrase", "text_en")' ]) . PHP_EOL;
// SEARCH PHRASE(doc.text, "search phrase", "text_en")

echo aqlSearch
([
    AQL::SEARCH         => 'PHRASE(doc.text, "search phrase")' ,
    AQL::ANALYZER       => 'text_en' ,
    AQL::SEARCH_OPTIONS => [ 'conditionOptimization' => ConditionOptimization::NONE ] ,
]) . PHP_EOL;
// SEARCH ANALYZER(PHRASE(doc.text, "search phrase"),"text_en") OPTIONS {"conditionOptimization":"none"}

echo aqlSearch(); // ''
Parameters
$init : array<string|int, mixed> = []

Array containing the key AQL::SEARCH with the expression to search, and optionally AQL::ANALYZER and AQL::SEARCH_OPTIONS.

Tags
throws
ReflectionException
see
https://docs.arangodb.com/stable/aql/high-level-operations/search
SearchOptions
analyzer()
aqlFor()
since
1.0.0

author Marc Alcaraz

Return values
string

The compiled AQL SEARCH clause, or an empty string if no search expression is provided.

aqlSort()

Builds an AQL `SORT` clause from a string or an array of sort expressions.

aqlSort(string|array<string|int, mixed>|null $expression) : string

This helper assembles a valid SORT operation for AQL queries. It accepts a single sort expression or multiple ones (as an array), and automatically joins them with commas when needed.

Each expression can be generated manually or using helpers like aqlAsc() and aqlDesc().

Example: with a single key

echo aqlSort('user.age ASC');
// → "SORT user.age ASC"

Example: with multiple expressions

echo aqlSort([
    aqlAsc('score', 'player'),
    aqlDesc('createdAt', 'doc')
]);
// → "SORT player.score ASC, doc.createdAt DESC"

Example: empty or null input

echo aqlSort(null);     // → ""
echo aqlSort([]);       // → ""
echo aqlSort('');       // → ""
Parameters
$expression : string|array<string|int, mixed>|null

The sort expression(s). Can be:

  • a string ("age ASC")
  • an array of expressions (["a ASC", "b DESC"])
  • null or empty string for no output
Tags
see
aqlAsc()

For ascending order helpers.

aqlDesc()

For descending order helpers.

https://docs.arangodb.com/stable/aql/fundamentals/sorting
since
1.0.0
author

Marc Alcaraz

Return values
string

The formatted SORT clause, or an empty string if no expression is provided.

aqlTraversal()

Builds a full **AQL traversal clause** for ArangoDB queries.

aqlTraversal([array{vertexRef?: string, edgeRef?: ?string, pathRef?: ?string, direction?: string, startVertex?: string, graph?: ?string, edgeCollection?: array|string|null, minDepth?: int|null, maxDepth?: int|null, prune?: string|array|null, options?: array|object|string|null} $init = [] ][, array<string|int, mixed>|null &$binds = null ]) : string

This helper constructs the canonical Arango Query Language (AQL) traversal expression, optionally including depth ranges, edge collections or graph names, direction, and bind variables.

It supports flexible initialization via the $init array, automatic bind variable injection, and seamless hydration of traversal options via TraversalOptions.

🧩 Canonical Form

FOR <vertexRef>, <edgeRef>, <pathRef>
IN <minDepth>..<maxDepth> <direction> <startVertex>
GRAPH <graphName>
OPTIONS { ... }

or, when using edge collections instead of a graph:

FOR <vertexRef>, <edgeRef>, <pathRef>
IN <minDepth>..<maxDepth> <direction> <startVertex>
<edgeCollection1>, <edgeCollection2>, ...

🔒 Bind Variables

If $binds is provided, both AQL::GRAPH and AQL::START_VERTEX (and optionally AQL::EDGE_COLLECTION) are automatically bound using aqlBind(), ensuring safe, injection-free query generation.

Example of secure binding:

$binds = [];
$aql = aqlTraversal([
AQL::GRAPH        => 'socialGraph',
AQL::START_VERTEX => '@start',
AQL::DIRECTION    => Traversal::INBOUND
], $binds);

print_r($binds);
// ['@start' => 'users/123', '@graph' => 'socialGraph']

💡 Usage Examples

1 - Simple graph traversal

echo aqlTraversal
([
    AQL::GRAPH         => 'socialGraph',
    AQL::START_VERTEX  => 'users/123',
]);
// FOR vertex IN OUTBOUND 'users/123' GRAPH 'socialGraph'

2 - Traversal with edges and path references

echo aqlTraversal
([
    AQL::VERTEX_REF    => 'v',
    AQL::EDGE_REF      => 'e',
    AQL::PATH_REF      => 'p',
    AQL::DIRECTION     => Traversal::INBOUND,
    AQL::GRAPH         => 'organization',
    AQL::START_VERTEX  => 'employees/42',
]);
// FOR v, e, p IN INBOUND 'employees/42' GRAPH 'organization'

3 - Depth-limited traversal

echo aqlTraversal
([
    AQL::GRAPH         => 'socialGraph',
    AQL::START_VERTEX  => 'users/123',
    AQL::MIN_DEPTH     => 1,
    AQL::MAX_DEPTH     => 3,
]);
// FOR vertex IN 1..3 OUTBOUND 'users/123' GRAPH 'socialGraph'

4 - Traversal using multiple edge collections

echo aqlTraversal
([
    AQL::EDGE_COLLECTION => ['follows', 'likes'],
    AQL::START_VERTEX    => 'users/123',
    AQL::DIRECTION       => Traversal::OUTBOUND,
]);
// FOR vertex IN OUTBOUND 'users/123' follows, likes

5 - With PRUNE condition

echo aqlTraversal
([
    AQL::GRAPH         => 'socialGraph',
    AQL::START_VERTEX  => 'users/123',
    AQL::PRUNE         => 'vertex.age < 18',
]);
// FOR vertex IN OUTBOUND 'users/123' GRAPH 'socialGraph' PRUNE vertex.age < 18

6 - With OPTIONS

echo aqlTraversal
([
    AQL::GRAPH         => 'companyGraph',
    AQL::START_VERTEX  => 'departments/1',
    AQL::OPTIONS       => ['bfs' => true, 'uniqueVertices' => 'global'],
]);
// FOR vertex IN OUTBOUND 'departments/1' GRAPH 'companyGraph' OPTIONS { "bfs": true, "uniqueVertices": "global" }
Parameters
$init : array{vertexRef?: string, edgeRef?: ?string, pathRef?: ?string, direction?: string, startVertex?: string, graph?: ?string, edgeCollection?: array|string|null, minDepth?: int|null, maxDepth?: int|null, prune?: string|array|null, options?: array|object|string|null} = []

Configuration for the traversal expression.

$binds : array<string|int, mixed>|null = null

Optional reference to a bind variable array; used for safe variable substitution.

Tags
throws
BindException

If a variable binding fails.

ConstantException

If the direction is not a valid Traversal constant.

ReflectionException

If aqlOptions() hydration fails due to reflection issues.

since
1.0.0
author

Marc Alcaraz

see
https://docs.arangodb.com/stable/aql/graphs/traversals/
Return values
string

The generated AQL traversal clause, or an empty string if input is invalid.

aqlTraversalRange()

Builds an AQL traversal range clause (e.g., `1..1`, `1..5`, `..2`, `3..`).

aqlTraversalRange([int|null $minDepth = null ][, int|null $maxDepth = null ][, array<string|int, mixed>|null &$binds = null ][, string $defaultRange = Char::EMPTY ]) : string

Supports

  • Fixed ranges (1..1, 2..5).
  • Open-ended ranges (1.. for "1 or more", ..3 for "up to 3").
  • Bind parameters to avoid query plan cache invalidation.

AQL Syntax

FOR v, e, p IN 1..1 OUTBOUND ...
FOR v, e, p IN 1..5 OUTBOUND ...
FOR v, e, p IN ..3 OUTBOUND ...  // 0 to 3
FOR v, e, p IN 2.. OUTBOUND ...  // 2 or more

Why use bind parameters?

Using placeholders like @minDepth and @maxDepth allows ArangoDB to reuse query execution plans, improving performance for repeated queries.

Examples

// Fixed range
echo aqlTraversalRange(1, 1);
// 1..1

// Open-ended max
echo aqlTraversalRange(1, null);
// 1..

// Open-ended min
echo aqlTraversalRange(null, 3);
// ..3

// With bind parameters
$binds = [];
echo aqlTraversalRange(1, 5, $binds);
// @minDepth..@maxDepth
// $binds = ['minDepth' => 1, 'maxDepth' => 5]

// With null parameters
echo aqlTraversalRange();
// ""
Parameters
$minDepth : int|null = null

Minimum depth (inclusive). If null, no lower bound.

$maxDepth : int|null = null

Maximum depth (inclusive). If null, no upper bound.

$binds : array<string|int, mixed>|null = null

Optional reference to a binds array for parameterized queries.

$defaultRange : string = Char::EMPTY

The default range if $minDepth=null && $maxDepth=null (Default "").

Tags
throws
BindException

If parameter binding fails.

since
1.0.0
author

Marc Alcaraz

Return values
string

AQL traversal range (e.g., "1..1", "@minDepth..@maxDepth").

aqlUpdate()

Partially modifies a document with the given attributes, by adding new and updating existing attributes.

aqlUpdate([ReplaceOptions|null, with?: string|null} $init = [] ][, string $operation = Operation::UPDATE ]) : string

Basic Syntax:*

UPDATE `document` IN `collection`
UPDATE `keyExpression` WITH `document` IN `collection`
Parameters
$init : ReplaceOptions|null, with?: string|null} = []

Initial options for the UPDATE or REPLACE statement, with the keys:

  • 'collection' : The name of the collection in which the document should be updated.
  • 'doc' : An object and contain the attributes and values to update.
  • 'options' : The default 'options' expression definition
  • 'rawValues' : array, keys whose values should be treated as raw AQL expressions - used with the 'with' option)
  • 'rawKeys' : array, keys which should be kept raw (their values are not wrapped or converted) - used with the 'with' option)
  • 'useSpace' : bool, add spaces around braces and after commas
  • 'with' : One or multiple collections for WITH clause -> WITH collection1 [, collection2 [, ... collectionN ] ]
$operation : string = Operation::UPDATE

The AQL operation to perform. Must be either Operation::UPDATE (default) or Operation::REPLACE.

If the "REPLACE" operation is used, see the replace method.

Tags
throws
ReflectionException

If options serialization or internal reflection fails.

Examples**

// 1. Basic UPDATE with default doc variable:
echo aqlUpdate
([
   'collection' => 'users',
   'doc'        => [ 'name' => 'John' ]
]);
// UPDATE {name:'John'} IN users

// 2. UPDATE using a custom document expression:
echo aqlUpdate
([
   'collection' => 'products',
   'doc'        => '{ price: 99.99 }'
]);
// UPDATE {price:99.99} IN products

// 3. REPLACE instead of UPDATE:
echo aqlUpdate
([
   'collection' => 'profiles',
   'doc'        => [ 'name' => 'Marc', 'age' => 42 ]
] , Operation::REPLACE ) ;
// REPLACE {name:'Marc',age:42} IN profiles

// 4. UPDATE with options array (doc):
echo aqlUpdate
([
   'collection' => 'events',
   'doc'        => 'doc',
   'options'    =>
   [
      'ignoreRevs' => true,
      'keepNull'   => false
   ]
]);
// UPDATE doc IN events OPTIONS {"ignoreRevs":true,"keepNull":false}

// 5. UPDATE with UpdateOptions object (doc):
echo aqlUpdate
([
   'collection' => 'products',
   'doc'        => [ 'price' => 42 ],
   'options'    => new UpdateOptions(['mergeObjects' => true])
]);
// UPDATE {price:42} IN products OPTIONS {"mergeObjects":true}

// 6. UPDATE using a key and WITH (no doc):
echo aqlUpdate
([
   'collection' => 'orders',
   'key'        => betweenQuotes('my_key'),
   'with'       => [ 'name' => 'eka', 'age' => 48 ]
]);
// UPDATE 'my_key' WITH {name:'eka',age:48} IN orders

// 7. UPDATE using a key in doc and WITH (no doc expression):
echo aqlUpdate
([
   'collection' => 'orders',
   'key'        => key('my_key', 'doc'),
   'with'       => [ 'name' => 'eka', 'age' => 48 ]
]);
// UPDATE doc.my_key WITH {name:'eka',age:48} IN orders
see
https://docs.arangodb.com/stable/aql/high-level-operations/update
UpdateOptions
author

Marc Alcaraz

since
1.0.0
Return values
string

aqlUpsert()

Prepare the query to update an existing document, or creates a new document if it does not exist.

aqlUpsert([JsonSerializable|null} $init = [] ]) : string
UPSERT [ searchExpression | FILTER filterExpression ]
INSERT insertExpression
UPDATE updateExpression
IN collection

Options in $init :

  • collection : The name of the collection
  • filter : The alternative filterExpression, this syntax for UPSERT operations allows you to use more flexible filter conditions beyond equality matches to look up documents.
  • search : The 'searchExpression' contains the document to be looked for. It must be an object literal (UPSERT { : , ... } ...) without dynamic attribute names. In case no such document can be found in collection, a new document is inserted into the collection as specified in the insertExpression.
  • insert : The document to insert in the collection if the document not exist.
  • update : The document to update in the collection.
  • options : The optional upsert options definition array or object.
  • return : optional expression to define the RETURN clause. Default is Clause::NEW. You can also use Clause::WITH_STATUS to return both the document and the type of operation.
Parameters
$init : JsonSerializable|null} = []

Configuration options for the UPSERT query.

Tags
throws
ReflectionException
UnsupportedOperationException
example

1 - Upsert with UPDATE

$query = aqlUpsert
([
    'search' => [['foo', 'bar']],
    'insert' => [['foo', 'bar']],
    'update' => [['foo', 'baz']],
]);
// Returns: "UPSERT {foo:'bar'} INSERT {foo:'bar'} UPDATE {foo:'baz'} IN @@collection RETURN NEW"

3 - Upsert with return including status

$query3 = aqlUpsert
([
    'search'  => [['foo', 'bar']],
    'insert'  => [['foo', 'bar']],
    'update'  => [['foo', 'baz']],
    'return'  => Clause::WITH_STATUS,
]);
// Returns:
// "UPSERT {foo:'bar'} INSERT {foo:'bar'} UPDATE {foo:'baz'} IN @@collection RETURN { doc: NEW, type: OLD ? 'update' : 'insert' }"
see
https://docs.arangodb.com/stable/aql/high-level-operations/upsert
since
1.0.0
author

Marc Alcaraz

Return values
string

The generated AQL UPSERT query.

aqlVectorSearch()

Builds a complete AQL approximate nearest-neighbour (ANN) query over a vector index.

aqlVectorSearch(string $collection, string $attribute, string $vector, int $limit[, string $metric = VectorMetric::COSINE ][, int|null $nProbe = null ][, string $docRef = 'doc' ][, string|null $return = null ]) : string

The generated query follows the canonical ANN form:

FOR <docRef> IN <collection>
  SORT APPROX_NEAR_<METRIC>(<docRef>.<attribute>, <vector>) <ASC|DESC>
  LIMIT <limit>
  RETURN <return>

The $metric selects both the AQL function and the sort direction, which is the part developers get wrong most often:

  • 'cosine'APPROX_NEAR_COSINE sorted DESC (closer to 1 is nearer),
  • 'l2'APPROX_NEAR_L2 sorted ASC (closer to 0 is nearer).

The metric must match the metric of the VectorIndex covering $attribute, otherwise the optimiser cannot accelerate the query.

Requires ArangoDB started with the experimental vector index feature.

Example: cosine search with a bound query vector

use function oihana\arango\db\operations\aqlVectorSearch;

$aql = aqlVectorSearch
(
    collection : 'items' ,
    attribute  : 'embedding' ,
    vector     : '@query' ,
    limit      : 10 ,
) ;
// FOR doc IN items SORT APPROX_NEAR_COSINE(doc.embedding,@query) DESC LIMIT 10 RETURN doc

Example: L2 search, custom nProbe, projection and iteration variable

$aql = aqlVectorSearch
(
    collection : 'items' ,
    attribute  : 'embedding' ,
    vector     : '@query' ,
    limit      : 5 ,
    metric     : 'l2' ,
    nProbe     : 20 ,
    docRef     : 'd' ,
    return     : '{ key: d._key, score: APPROX_NEAR_L2(d.embedding, @query) }' ,
) ;
// FOR d IN items SORT APPROX_NEAR_L2(d.embedding,@query,{"nProbe":20}) ASC LIMIT 5
//   RETURN { key: d._key, score: APPROX_NEAR_L2(d.embedding, @query) }
Parameters
$collection : string

The collection to scan (or any AQL iterable expression).

$attribute : string

The document attribute holding the indexed vector (e.g. 'embedding').

$vector : string

The query vector — typically a bind placeholder ('@query') or an AQL array literal.

$limit : int

The number of nearest neighbours to return (the LIMIT).

$metric : string = VectorMetric::COSINE

The similarity metric: 'cosine' (default) or 'l2'. Must match the vector index.

$nProbe : int|null = null

Optional number of neighbouring centroids to probe (higher = more accurate, slower).

$docRef : string = 'doc'

The iteration variable name (default 'doc').

$return : string|null = null

Optional RETURN expression. Defaults to the iteration variable (the whole document).

Tags
throws
InvalidArgumentException

If $metric is neither 'cosine' nor 'l2'.

see
https://docs.arangodb.com/stable/aql/functions/vector/
approxNearCosine()
approxNearL2()
since
1.1.0
author

Marc Alcaraz

Return values
string

The complete AQL ANN query.

aqlWindow()

Builds an AQL `WINDOW` clause for sliding-window aggregation (running totals, rolling averages, and other statistical properties over related rows).

aqlWindow([array<string|int, mixed> $init = [] ]) : string

Two forms are supported, selected by the presence of AQL::RANGE_VALUE:

Row-based (a fixed number of adjacent rows) — no rangeValue:

WINDOW { preceding: numPrecedingRows, following: numFollowingRows }
AGGREGATE variableName = aggregateExpression

Range-based (a value or duration range around rangeValue) — with rangeValue:

WINDOW rangeValue WITH { preceding: offsetPreceding, following: offsetFollowing }
AGGREGATE variableName = aggregateExpression

The WITH keyword here belongs to the range-based WINDOW syntax and is unrelated to the collection-declaring WITH operation (aqlWith()).

Supported $init keys

Key Type Description
AQL::AGGREGATE array Aggregation expressions, e.g. ['rollingAvg' => 'AVG(doc.val)']. Required.
AQL::PRECEDING int float
AQL::FOLLOWING int float
AQL::RANGE_VALUE string The row-value expression for a range-based window (e.g. 'doc.time'). When set, the range-based form is emitted.

Bound values are serialized as-is when numeric and single-quoted when given as strings (so ISO 8601 durations like PT1H / P1Y6M are emitted as 'PT1H'). A bound that is null is omitted from the { … } object.

For a running total (aggregate every row from the start up to the current one), use the string 'unbounded' as the preceding bound — e.g. [ AQL::PRECEDING => 'unbounded' , AQL::FOLLOWING => 0 , … ] yields WINDOW { preceding: 'unbounded', following: 0 } AGGREGATE ….

Examples

Row-based rolling average (previous, current, next row):

echo aqlWindow
([
    AQL::PRECEDING => 1 ,
    AQL::FOLLOWING => 1 ,
    AQL::AGGREGATE => [ 'rollingAvg' => 'AVG(doc.val)' ] ,
]);
// WINDOW { preceding: 1, following: 1 } AGGREGATE rollingAvg = AVG(doc.val)

Range-based sum over a duration window:

echo aqlWindow
([
    AQL::RANGE_VALUE => 'doc.time' ,
    AQL::PRECEDING   => 'PT1H' ,
    AQL::FOLLOWING   => 0 ,
    AQL::AGGREGATE   => [ 'total' => 'SUM(doc.val)' ] ,
]);
// WINDOW doc.time WITH { preceding: 'PT1H', following: 0 } AGGREGATE total = SUM(doc.val)
Parameters
$init : array<string|int, mixed> = []

Associative array of window options.

Tags
see
https://docs.arangodb.com/stable/aql/high-level-operations/window/
since
1.0.0
author

Marc Alcaraz

Return values
string

The compiled AQL WINDOW clause, or an empty string when no aggregate is supplied (a WINDOW without aggregation is meaningless).

aqlWindowBounds()

Serializes the `{ preceding: …, following: … }` bounds object of a `WINDOW` clause.

aqlWindowBounds(int|float|string|null $preceding, int|float|string|null $following) : string

Numeric bounds are emitted bare; string bounds are single-quoted (ISO 8601 durations such as PT1H, or the 'unbounded' keyword). A null bound is omitted from the object.

echo aqlWindowBounds( 1 , 1 ) ;             // { preceding: 1, following: 1 }
echo aqlWindowBounds( 'unbounded' , 0 ) ;   // { preceding: 'unbounded', following: 0 }
echo aqlWindowBounds( 0 , null ) ;          // { preceding: 0 }
echo aqlWindowBounds( null , null ) ;       // {  }
Parameters
$preceding : int|float|string|null

Lower window bound.

$following : int|float|string|null

Upper window bound.

Tags
see
aqlWindow()
since
1.0.0
author

Marc Alcaraz

Return values
string

The bounds object literal, e.g. { preceding: 1, following: 1 }.

aqlWith()

Generates an AQL `WITH` clause for one or more collections.

aqlWith(string ...$collections) : string

The WITH clause restricts the query to only access the specified collections.

Syntax:

WITH collection1, collection2, ...

Example usage:

echo aqlWith('users');              // "WITH users"
echo aqlWith('users', 'orders');    // "WITH users, orders"
echo aqlWith();                     // ""
Parameters
$collections : string

List of collection names to include in the query.

Tags
see
https://docs.arangodb.com/stable/aql/high-level-operations/with
since
1.0.0
author

Marc Alcaraz

Return values
string

The generated AQL WITH clause, or an empty string if none provided.

On this page

Search results