mirror of https://gitee.com/bigwinds/arangodb
306 lines
6.8 KiB
Markdown
306 lines
6.8 KiB
Markdown
---
|
|
layout: default
|
|
description: In order to access a named attribute from all elements in an array easily, AQLoffers the shortcut operator [*] for array variable expansion
|
|
---
|
|
Array Operators
|
|
===============
|
|
|
|
|
|
Array expansion
|
|
---------------
|
|
|
|
In order to access a named attribute from all elements in an array easily, AQL
|
|
offers the shortcut operator `[*]` for array variable expansion.
|
|
|
|
Using the `[*]` operator with an array variable will iterate over all elements
|
|
in the array, thus allowing to access a particular attribute of each element. It is
|
|
required that the expanded variable is an array. The result of the `[*]`
|
|
operator is again an array.
|
|
|
|
To demonstrate the array expansion operator, let's go on with the following three
|
|
example *users* documents:
|
|
|
|
```json
|
|
[
|
|
{
|
|
"name": "john",
|
|
"age": 35,
|
|
"friends": [
|
|
{ "name": "tina", "age": 43 },
|
|
{ "name": "helga", "age": 52 },
|
|
{ "name": "alfred", "age": 34 }
|
|
]
|
|
},
|
|
{
|
|
"name": "yves",
|
|
"age": 24,
|
|
"friends": [
|
|
{ "name": "sergei", "age": 27 },
|
|
{ "name": "tiffany", "age": 25 }
|
|
]
|
|
},
|
|
{
|
|
"name": "sandra",
|
|
"age": 40,
|
|
"friends": [
|
|
{ "name": "bob", "age": 32 },
|
|
{ "name": "elena", "age": 48 }
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
With the `[*]` operator it becomes easy to query just the names of the
|
|
friends for each user:
|
|
|
|
```
|
|
FOR u IN users
|
|
RETURN { name: u.name, friends: u.friends[*].name }
|
|
```
|
|
|
|
This will produce:
|
|
|
|
```json
|
|
[
|
|
{ "name" : "john", "friends" : [ "tina", "helga", "alfred" ] },
|
|
{ "name" : "yves", "friends" : [ "sergei", "tiffany" ] },
|
|
{ "name" : "sandra", "friends" : [ "bob", "elena" ] }
|
|
]
|
|
```
|
|
|
|
This is a shortcut for the longer, semantically equivalent query:
|
|
|
|
```js
|
|
FOR u IN users
|
|
RETURN { name: u.name, friends: (FOR f IN u.friends RETURN f.name) }
|
|
```
|
|
|
|
Array contraction
|
|
-----------------
|
|
|
|
In order to collapse (or flatten) results in nested arrays, AQL provides the `[**]`
|
|
operator. It works similar to the `[*]` operator, but additionally collapses nested
|
|
arrays.
|
|
|
|
How many levels are collapsed is determined by the amount of asterisk characters used.
|
|
`[**]` collapses one level of nesting - just like `FLATTEN(array)` or `FLATTEN(array, 1)`
|
|
would do -, `[***]` collapses two levels - the equivalent to `FLATTEN(array, 2)` - and
|
|
so on.
|
|
|
|
Let's compare the array expansion operator with an array contraction operator.
|
|
For example, the following query produces an array of friend names per user:
|
|
|
|
```js
|
|
FOR u IN users
|
|
RETURN u.friends[*].name
|
|
```
|
|
|
|
As we have multiple users, the overall result is a nested array:
|
|
|
|
```json
|
|
[
|
|
[
|
|
"tina",
|
|
"helga",
|
|
"alfred"
|
|
],
|
|
[
|
|
"sergei",
|
|
"tiffany"
|
|
],
|
|
[
|
|
"bob",
|
|
"elena"
|
|
]
|
|
]
|
|
```
|
|
|
|
If the goal is to get rid of the nested array, we can apply the `[**]` operator on the
|
|
result. But simply appending `[**]` to the query won't help, because *u.friends*
|
|
is not a nested (multi-dimensional) array, but a simple (one-dimensional) array. Still,
|
|
the `[**]` can be used if it has access to a multi-dimensional nested result.
|
|
|
|
We can extend above query as follows and still create the same nested result:
|
|
|
|
```js
|
|
RETURN (
|
|
FOR u IN users RETURN u.friends[*].name
|
|
)
|
|
```
|
|
|
|
By now appending the `[**]` operator at the end of the query...
|
|
|
|
```js
|
|
RETURN (
|
|
FOR u IN users RETURN u.friends[*].name
|
|
)[**]
|
|
```
|
|
|
|
... the query result becomes:
|
|
|
|
```json
|
|
[
|
|
[
|
|
"tina",
|
|
"helga",
|
|
"alfred",
|
|
"sergei",
|
|
"tiffany",
|
|
"bob",
|
|
"elena"
|
|
]
|
|
]
|
|
```
|
|
|
|
Note that the elements are not de-duplicated. For a flat array with only unique
|
|
elements, a combination of [UNIQUE()](functions-array.html#unique) and
|
|
[FLATTEN()](functions-array.html#flatten) is advisable.
|
|
|
|
Inline expressions
|
|
------------------
|
|
|
|
It is possible to filter elements while iterating over an array, to limit the amount
|
|
of returned elements and to create a projection using the current array element.
|
|
Sorting is not supported by this shorthand form.
|
|
|
|
These inline expressions can follow array expansion and contraction operators
|
|
`[* ...]`, `[** ...]` etc. The keywords `FILTER`, `LIMIT` and `RETURN`
|
|
must occur in this order if they are used in combination, and can only occur once:
|
|
|
|
`anyArray[* FILTER conditions LIMIT skip,limit RETURN projection]`
|
|
|
|
Example with nested numbers and array contraction:
|
|
|
|
```js
|
|
LET arr = [ [ 1, 2 ], 3, [ 4, 5 ], 6 ]
|
|
RETURN arr[** FILTER CURRENT % 2 == 0]
|
|
```
|
|
|
|
All even numbers are returned in a flat array:
|
|
|
|
```json
|
|
[
|
|
[ 2, 4, 6 ]
|
|
]
|
|
```
|
|
|
|
Complex example with multiple conditions, limit and projection:
|
|
|
|
```js
|
|
FOR u IN users
|
|
RETURN {
|
|
name: u.name,
|
|
friends: u.friends[* FILTER CONTAINS(CURRENT.name, "a") AND CURRENT.age > 40
|
|
LIMIT 2
|
|
RETURN CONCAT(CURRENT.name, " is ", CURRENT.age)
|
|
]
|
|
}
|
|
```
|
|
|
|
No more than two computed strings based on *friends* with an `a` in their name and
|
|
older than 40 years are returned per user:
|
|
|
|
```json
|
|
[
|
|
{
|
|
"name": "john",
|
|
"friends": [
|
|
"tina is 43",
|
|
"helga is 52"
|
|
]
|
|
},
|
|
{
|
|
"name": "sandra",
|
|
"friends": [
|
|
"elena is 48"
|
|
]
|
|
},
|
|
{
|
|
"name": "yves",
|
|
"friends": []
|
|
}
|
|
]
|
|
```
|
|
|
|
### Inline filter
|
|
|
|
To return only the names of friends that have an *age* value
|
|
higher than the user herself, an inline `FILTER` can be used:
|
|
|
|
```js
|
|
FOR u IN users
|
|
RETURN { name: u.name, friends: u.friends[* FILTER CURRENT.age > u.age].name }
|
|
```
|
|
|
|
The pseudo-variable *CURRENT* can be used to access the current array element.
|
|
The `FILTER` condition can refer to *CURRENT* or any variables valid in the
|
|
outer scope.
|
|
|
|
### Inline limit
|
|
|
|
The number of elements returned can be restricted with `LIMIT`. It works the same
|
|
as the [limit operation](operations-limit.html). `LIMIT` must come after `FILTER`
|
|
and before `RETURN`, if they are present.
|
|
|
|
```js
|
|
FOR u IN users
|
|
RETURN { name: u.name, friends: u.friends[* LIMIT 1].name }
|
|
```
|
|
|
|
Above example returns one friend each:
|
|
|
|
```json
|
|
[
|
|
{ "name": "john", "friends": [ "tina" ] },
|
|
{ "name": "sandra", "friends": [ "bob" ] },
|
|
{ "name": "yves", "friends": [ "sergei" ] }
|
|
]
|
|
```
|
|
|
|
A number of elements can also be skipped and up to *n* returned:
|
|
|
|
```js
|
|
FOR u IN users
|
|
RETURN { name: u.name, friends: u.friends[* LIMIT 1,2].name }
|
|
```
|
|
|
|
The example query skips the first friend and returns two friends at most
|
|
per user:
|
|
|
|
```json
|
|
[
|
|
{ "name": "john", "friends": [ "helga", "alfred" ] },
|
|
{ "name": "sandra", "friends": [ "elena" ] },
|
|
{ "name": "yves", "friends": [ "tiffany" ] }
|
|
]
|
|
```
|
|
|
|
### Inline projection
|
|
|
|
To return a projection of the current element, use `RETURN`. If a `FILTER` is
|
|
also present, `RETURN` must come later.
|
|
|
|
```js
|
|
FOR u IN users
|
|
RETURN u.friends[* RETURN CONCAT(CURRENT.name, " is a friend of ", u.name)]
|
|
```
|
|
|
|
The above will return:
|
|
|
|
```json
|
|
[
|
|
[
|
|
"tina is a friend of john",
|
|
"helga is a friend of john",
|
|
"alfred is a friend of john"
|
|
],
|
|
[
|
|
"sergei is a friend of yves",
|
|
"tiffany is a friend of yves"
|
|
],
|
|
[
|
|
"bob is a friend of sandra",
|
|
"elena is a friend of sandra"
|
|
]
|
|
]
|
|
``` |