mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/arangodb/arangodb into devel
This commit is contained in:
commit
1f9f46bd13
|
@ -0,0 +1 @@
|
|||
!CHAPTER Common Errors
|
|
@ -8,7 +8,7 @@ AQL supports the following data-modification operations:
|
|||
- **REMOVE**: remove existing documents from a collection
|
||||
- **UPSERT**: conditionally insert or update documents in a collection
|
||||
|
||||
Those operations are detailed in the chapter [High Level Operations](Operations.md).
|
||||
Those operations are detailed in the chapter [High Level Operations](Operations/README.md).
|
||||
|
||||
|
||||
!SUBSECTION Modifying a single document
|
||||
|
@ -16,34 +16,49 @@ Those operations are detailed in the chapter [High Level Operations](Operations.
|
|||
Let's start with the basics: `INSERT`, `UPDATE` and `REMOVE` operations on single documents.
|
||||
Here is an example that insert a document in an existing collection *users*:
|
||||
|
||||
INSERT {firstName:'Anna', name:'Pavlova', profession:'artist'} IN users
|
||||
```js
|
||||
INSERT { firstName: "Anna", name: "Pavlova", profession: "artist" } IN users
|
||||
```
|
||||
|
||||
You may provide a key for the new document; if not provided, ArangoDB will create one for you.
|
||||
|
||||
INSERT {_key:'GilbertoGil', firstName:'Gilberto', name:'Gil', city:'Fortalezza'} IN users
|
||||
```js
|
||||
INSERT { _key: "GilbertoGil", firstName: "Gilberto", name: "Gil", city: "Fortalezza" } IN users
|
||||
```
|
||||
|
||||
As Arango is schema-free, attributes of the documents may vary:
|
||||
|
||||
INSERT {_key:'PhilCarpenter', firstName:'Phil', name:'Carpenter', middleName:'G.',status:'inactive', } IN users
|
||||
```js
|
||||
INSERT { _key: "PhilCarpenter", firstName: "Phil", name: "Carpenter", middleName: "G.", status: "inactive" } IN users
|
||||
```
|
||||
|
||||
INSERT {_key:'NatachaDeclerck', firstName:'Natacha', name:'Declerck', location:'Antwerp'} IN users
|
||||
```js
|
||||
INSERT { _key: "NatachaDeclerck", firstName: "Natacha", name: "Declerck", location: "Antwerp" } IN users
|
||||
```
|
||||
|
||||
Update is quite simple. The following AQL statement will add or change the attributes status and location
|
||||
|
||||
UPDATE 'PhilCarpenter' WITH { status:'active', location:'Beijing' } IN users
|
||||
```js
|
||||
UPDATE "PhilCarpenter" WITH { status: "active", location: "Beijing" } IN users
|
||||
```
|
||||
|
||||
Replace is an alternative to update where all attributes of the document are replaced.
|
||||
|
||||
REPLACE { _key: 'NatachaDeclerck', firstName:'Natacha', name:'Leclerc', status: 'active', level:'premium' } IN users
|
||||
```js
|
||||
REPLACE { _key: "NatachaDeclerck", firstName: "Natacha", name: "Leclerc", status: "active", level: "premium" } IN users
|
||||
```
|
||||
|
||||
Removing a document if you know its key is simple as well :
|
||||
|
||||
REMOVE 'GilbertoGil' IN users
|
||||
```js
|
||||
REMOVE "GilbertoGil" IN users
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
REMOVE {_key:'GilbertoGil'} IN users
|
||||
|
||||
```js
|
||||
REMOVE { _key: "GilbertoGil" } IN users
|
||||
```
|
||||
|
||||
!SUBSECTION Modifying multiple documents
|
||||
|
||||
|
@ -54,26 +69,30 @@ iterate over a given list of documents. They can optionally be combined with
|
|||
Let's start with an example that modifies existing documents in a collection
|
||||
*users* that match some condition:
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.status == 'not active'
|
||||
UPDATE u WITH { status: 'inactive' } IN users
|
||||
|
||||
```js
|
||||
FOR u IN users
|
||||
FILTER u.status == "not active"
|
||||
UPDATE u WITH { status: "inactive" } IN users
|
||||
```
|
||||
|
||||
|
||||
Now, let's copy the contents of the collection *users* into the collection
|
||||
*backup*:
|
||||
|
||||
FOR u IN users
|
||||
INSERT u IN backup
|
||||
```js
|
||||
FOR u IN users
|
||||
INSERT u IN backup
|
||||
```
|
||||
|
||||
As a final example, let's find some documents in collection *users* and
|
||||
remove them from collection *backup*. The link between the documents in both
|
||||
collections is established via the documents' keys:
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.status == 'deleted'
|
||||
REMOVE u IN backup
|
||||
|
||||
```js
|
||||
FOR u IN users
|
||||
FILTER u.status == "deleted"
|
||||
REMOVE u IN backup
|
||||
```
|
||||
|
||||
!SUBSECTION Returning documents
|
||||
|
||||
|
@ -81,19 +100,25 @@ Data-modification queries can optionally return documents. In order to reference
|
|||
the inserted, removed or modified documents in a `RETURN` statement, data-modification
|
||||
statements introduce the `OLD` and/or `NEW` pseudo-values:
|
||||
|
||||
FOR i IN 1..100
|
||||
INSERT { value: i } IN test
|
||||
RETURN NEW
|
||||
```js
|
||||
FOR i IN 1..100
|
||||
INSERT { value: i } IN test
|
||||
RETURN NEW
|
||||
```
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.status == 'deleted'
|
||||
REMOVE u IN users
|
||||
RETURN OLD
|
||||
```js
|
||||
FOR u IN users
|
||||
FILTER u.status == "deleted"
|
||||
REMOVE u IN users
|
||||
RETURN OLD
|
||||
```
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.status == 'not active'
|
||||
UPDATE u WITH { status: 'inactive' } IN users
|
||||
RETURN NEW
|
||||
```js
|
||||
FOR u IN users
|
||||
FILTER u.status == "not active"
|
||||
UPDATE u WITH { status: "inactive" } IN users
|
||||
RETURN NEW
|
||||
```
|
||||
|
||||
`NEW` refers to the inserted or modified document revision, and `OLD` refers
|
||||
to the document revision before update or removal. `INSERT` statements can
|
||||
|
@ -112,21 +137,23 @@ by queries.
|
|||
|
||||
For example, the following query will return only the keys of the inserted documents:
|
||||
|
||||
FOR i IN 1..100
|
||||
INSERT { value: i } IN test
|
||||
RETURN NEW._key
|
||||
|
||||
```js
|
||||
FOR i IN 1..100
|
||||
INSERT { value: i } IN test
|
||||
RETURN NEW._key
|
||||
```
|
||||
|
||||
!SUBSUBSECTION Using OLD and NEW in the same query
|
||||
|
||||
For `UPDATE`, `REPLACE` and `UPSERT` statements, both `OLD` and `NEW` can be used
|
||||
to return the previous revision of a document together with the updated revision:
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.status == 'not active'
|
||||
UPDATE u WITH { status: 'inactive' } IN users
|
||||
RETURN { old: OLD, new: NEW }
|
||||
|
||||
```js
|
||||
FOR u IN users
|
||||
FILTER u.status == "not active"
|
||||
UPDATE u WITH { status: "inactive" } IN users
|
||||
RETURN { old: OLD, new: NEW }
|
||||
```
|
||||
|
||||
!SUBSUBSECTION Calculations with OLD or NEW
|
||||
|
||||
|
@ -137,18 +164,20 @@ updated, or a new document was inserted. It does so by checking the `OLD` variab
|
|||
after the `UPSERT` and using a `LET` statement to store a temporary string for
|
||||
the operation type:
|
||||
|
||||
UPSERT { name: 'test' }
|
||||
INSERT { name: 'test' }
|
||||
UPDATE { } IN users
|
||||
LET opType = IS_NULL(old) ? 'insert' : 'update'
|
||||
RETURN { _key: NEW._key, type: opType }
|
||||
|
||||
```js
|
||||
UPSERT { name: "test" }
|
||||
INSERT { name: "test" }
|
||||
UPDATE { } IN users
|
||||
LET opType = IS_NULL(old) ? "insert" : "update"
|
||||
RETURN { _key: NEW._key, type: opType }
|
||||
```
|
||||
|
||||
!SUBSECTION Restrictions
|
||||
|
||||
The name of the modified collection (*users* and *backup* in the above cases)
|
||||
must be known to the AQL executor at query-compile time and cannot change at
|
||||
runtime. Using a bind parameter to specify the [collection name](../Glossary/README.md#collection-name) is allowed.
|
||||
runtime. Using a bind parameter to specify the
|
||||
[collection name](../Users/Appendix/Glossary.html#collection-name) is allowed.
|
||||
|
||||
Data-modification queries are restricted to modifying data in a single
|
||||
collection per query. That means a data-modification query cannot modify
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
!CHAPTER Combining Graph Traversals
|
||||
!SUBSECTION Finding the start vertex via a geo query
|
||||
Our first example will locate the start vertex for a graph traversal via [a geo index](../IndexHandling/Geo.md).
|
||||
We use [the city graph](../Graphs/README.md#the-city-graph) and its geo indices:
|
||||
Our first example will locate the start vertex for a graph traversal via [a geo index](../../Users/Indexing/Geo.html).
|
||||
We use [the city graph](../../Users/Graphs/index.html#the-city-graph) and its geo indices:
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
@startDocuBlockInline COMBINING_GRAPH_01_create_graph
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
!SECTION Amount of documents in a collection
|
||||
|
||||
To return the count of documents that currently exist in a collection,
|
||||
you can call the [LENGTH() function](../Aql/ArrayFunctions.md#length):
|
||||
you can call the [LENGTH() function](../Functions/Array.md#length):
|
||||
|
||||
```
|
||||
RETURN LENGTH(collection)
|
||||
|
@ -11,11 +11,13 @@ RETURN LENGTH(collection)
|
|||
|
||||
This type of call is optimized since 2.8 (no unnecessary intermediate result
|
||||
is built up in memory) and it is therefore the prefered way to determine the count.
|
||||
Internally, [COLLECTION_COUNT()](../Functions/Miscellaneous.md#collectioncount) is called.
|
||||
|
||||
In earlier versions with `COLLECT ... WITH COUNT INTO` available (since 2.4),
|
||||
you may use the following code for better performance instead:
|
||||
you may use the following code instead of *LENGTH()* for better performance:
|
||||
|
||||
```
|
||||
FOR doc IN collection
|
||||
COLLECT WITH COUNT INTO length
|
||||
RETURN length
|
||||
COLLECT WITH COUNT INTO length
|
||||
RETURN length
|
||||
```
|
||||
|
|
|
@ -9,29 +9,29 @@ added in the query if required.
|
|||
*COLLECT* can be used to make a result set unique. The following query will return each distinct
|
||||
`age` attribute value only once:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
COLLECT age = u.age
|
||||
RETURN age
|
||||
```js
|
||||
FOR u IN users
|
||||
COLLECT age = u.age
|
||||
RETURN age
|
||||
```
|
||||
|
||||
This is grouping without tracking the group values, but just the group criterion (*age*) value.
|
||||
|
||||
Grouping can also be done on multiple levels using *COLLECT*:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
COLLECT status = u.status, age = u.age
|
||||
RETURN { status, age }
|
||||
```js
|
||||
FOR u IN users
|
||||
COLLECT status = u.status, age = u.age
|
||||
RETURN { status, age }
|
||||
```
|
||||
|
||||
|
||||
Alternatively *RETURN DISTINCT* can be used to make a result set unique. *RETURN DISTINCT* supports a
|
||||
Alternatively *RETURN DISTINCT* can be used to make a result set unique. *RETURN DISTINCT* supports a
|
||||
single criterion only:
|
||||
|
||||
```
|
||||
```js
|
||||
FOR u IN users
|
||||
RETURN DISTINCT u.age
|
||||
RETURN DISTINCT u.age
|
||||
```
|
||||
|
||||
Note: the order of results is undefined for *RETURN DISTINCT*.
|
||||
|
@ -41,70 +41,72 @@ Note: the order of results is undefined for *RETURN DISTINCT*.
|
|||
To group users by age, and return the names of the users with the highest ages,
|
||||
we'll issue a query like this:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT age = u.age INTO usersByAge
|
||||
SORT age DESC LIMIT 0, 5
|
||||
RETURN {
|
||||
```js
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT age = u.age INTO usersByAge
|
||||
SORT age DESC LIMIT 0, 5
|
||||
RETURN {
|
||||
age,
|
||||
users : usersByAge[*].u.name
|
||||
users: usersByAge[*].u.name
|
||||
}
|
||||
```
|
||||
|
||||
[
|
||||
{
|
||||
"age" : 37,
|
||||
"users" : [
|
||||
"John",
|
||||
"Sophia"
|
||||
]
|
||||
},
|
||||
{
|
||||
"age" : 36,
|
||||
"users" : [
|
||||
"Fred",
|
||||
"Emma"
|
||||
]
|
||||
},
|
||||
{
|
||||
"age" : 34,
|
||||
"users" : [
|
||||
"Madison"
|
||||
]
|
||||
},
|
||||
{
|
||||
"age" : 33,
|
||||
"users" : [
|
||||
"Chloe",
|
||||
"Michael"
|
||||
]
|
||||
},
|
||||
{
|
||||
"age" : 32,
|
||||
"users" : [
|
||||
"Alexander"
|
||||
]
|
||||
}
|
||||
```json
|
||||
[
|
||||
{
|
||||
"age": 37,
|
||||
"users": [
|
||||
"John",
|
||||
"Sophia"
|
||||
]
|
||||
},
|
||||
{
|
||||
"age": 36,
|
||||
"users": [
|
||||
"Fred",
|
||||
"Emma"
|
||||
]
|
||||
},
|
||||
{
|
||||
"age": 34,
|
||||
"users": [
|
||||
"Madison"
|
||||
]
|
||||
},
|
||||
{
|
||||
"age": 33,
|
||||
"users": [
|
||||
"Chloe",
|
||||
"Michael"
|
||||
]
|
||||
},
|
||||
{
|
||||
"age": 32,
|
||||
"users": [
|
||||
"Alexander"
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
The query will put all users together by their *age* attribute. There will be one
|
||||
result document per distinct *age* value (let aside the *LIMIT*). For each group,
|
||||
we have access to the matching document via the *usersByAge* variable introduced in
|
||||
the *COLLECT* statement.
|
||||
the *COLLECT* statement.
|
||||
|
||||
!SUBSECTION Variable Expansion
|
||||
|
||||
The *usersByAge* variable contains the full documents found, and as we're only
|
||||
interested in user names, we'll use the expansion operator <i>[\*]</i> to extract just the
|
||||
The *usersByAge* variable contains the full documents found, and as we're only
|
||||
interested in user names, we'll use the expansion operator <i>[\*]</i> to extract just the
|
||||
*name* attribute of all user documents in each group.
|
||||
|
||||
The <i>[\*]</i> expansion operator is just a handy short-cut. Instead of <i>usersByAge[\*].u.name</i>
|
||||
we could also write:
|
||||
|
||||
```
|
||||
```js
|
||||
FOR temp IN usersByAge
|
||||
RETURN temp.u.name
|
||||
RETURN temp.u.name
|
||||
```
|
||||
|
||||
!SUBSECTION Grouping by multiple criteria
|
||||
|
@ -113,42 +115,44 @@ To group by multiple criteria, we'll use multiple arguments in the *COLLECT* cla
|
|||
For example, to group users by *ageGroup* (a derived value we need to calculate first)
|
||||
and then by *gender*, we'll do:
|
||||
|
||||
```js
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT ageGroup = FLOOR(u.age / 5) * 5,
|
||||
gender = u.gender INTO group
|
||||
SORT ageGroup DESC
|
||||
RETURN {
|
||||
ageGroup,
|
||||
gender
|
||||
}
|
||||
```
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT ageGroup = FLOOR(u.age / 5) * 5,
|
||||
gender = u.gender INTO group
|
||||
SORT ageGroup DESC
|
||||
RETURN {
|
||||
ageGroup,
|
||||
gender
|
||||
}
|
||||
|
||||
[
|
||||
{
|
||||
"ageGroup" : 35,
|
||||
"gender" : "f"
|
||||
},
|
||||
{
|
||||
"ageGroup" : 35,
|
||||
"gender" : "m"
|
||||
},
|
||||
{
|
||||
"ageGroup" : 30,
|
||||
"gender" : "f"
|
||||
},
|
||||
{
|
||||
"ageGroup" : 30,
|
||||
"gender" : "m"
|
||||
},
|
||||
{
|
||||
"ageGroup" : 25,
|
||||
"gender" : "f"
|
||||
},
|
||||
{
|
||||
"ageGroup" : 25,
|
||||
"gender" : "m"
|
||||
}
|
||||
```json
|
||||
[
|
||||
{
|
||||
"ageGroup": 35,
|
||||
"gender": "f"
|
||||
},
|
||||
{
|
||||
"ageGroup": 35,
|
||||
"gender": "m"
|
||||
},
|
||||
{
|
||||
"ageGroup": 30,
|
||||
"gender": "f"
|
||||
},
|
||||
{
|
||||
"ageGroup": 30,
|
||||
"gender": "m"
|
||||
},
|
||||
{
|
||||
"ageGroup": 25,
|
||||
"gender": "f"
|
||||
},
|
||||
{
|
||||
"ageGroup": 25,
|
||||
"gender": "m"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
@ -158,49 +162,51 @@ If the goal is to count the number of values in each group, AQL provides the spe
|
|||
*COLLECT WITH COUNT INTO* syntax. This is a simple variant for grouping with an additional
|
||||
group length calculation:
|
||||
|
||||
```js
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT ageGroup = FLOOR(u.age / 5) * 5,
|
||||
gender = u.gender WITH COUNT INTO numUsers
|
||||
SORT ageGroup DESC
|
||||
RETURN {
|
||||
ageGroup,
|
||||
gender,
|
||||
numUsers
|
||||
}
|
||||
```
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT ageGroup = FLOOR(u.age / 5) * 5,
|
||||
gender = u.gender WITH COUNT INTO numUsers
|
||||
SORT ageGroup DESC
|
||||
RETURN {
|
||||
ageGroup,
|
||||
gender,
|
||||
numUsers
|
||||
}
|
||||
|
||||
[
|
||||
{
|
||||
"ageGroup" : 35,
|
||||
"gender" : "f",
|
||||
"numUsers" : 2
|
||||
},
|
||||
{
|
||||
"ageGroup" : 35,
|
||||
"gender" : "m",
|
||||
"numUsers" : 2
|
||||
},
|
||||
{
|
||||
"ageGroup" : 30,
|
||||
"gender" : "f",
|
||||
"numUsers" : 4
|
||||
},
|
||||
{
|
||||
"ageGroup" : 30,
|
||||
"gender" : "m",
|
||||
"numUsers" : 4
|
||||
},
|
||||
{
|
||||
"ageGroup" : 25,
|
||||
"gender" : "f",
|
||||
"numUsers" : 2
|
||||
},
|
||||
{
|
||||
"ageGroup" : 25,
|
||||
"gender" : "m",
|
||||
"numUsers" : 2
|
||||
}
|
||||
```json
|
||||
[
|
||||
{
|
||||
"ageGroup": 35,
|
||||
"gender": "f",
|
||||
"numUsers": 2
|
||||
},
|
||||
{
|
||||
"ageGroup": 35,
|
||||
"gender": "m",
|
||||
"numUsers": 2
|
||||
},
|
||||
{
|
||||
"ageGroup": 30,
|
||||
"gender": "f",
|
||||
"numUsers": 4
|
||||
},
|
||||
{
|
||||
"ageGroup": 30,
|
||||
"gender": "m",
|
||||
"numUsers": 4
|
||||
},
|
||||
{
|
||||
"ageGroup": 25,
|
||||
"gender": "f",
|
||||
"numUsers": 2
|
||||
},
|
||||
{
|
||||
"ageGroup": 25,
|
||||
"gender": "m",
|
||||
"numUsers": 2
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
@ -209,45 +215,47 @@ FOR u IN users
|
|||
Adding further aggregation is also simple in AQL by using an *AGGREGATE* clause
|
||||
in the *COLLECT*:
|
||||
|
||||
```js
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT ageGroup = FLOOR(u.age / 5) * 5,
|
||||
gender = u.gender
|
||||
AGGREGATE numUsers = LENGTH(1),
|
||||
minAge = MIN(u.age),
|
||||
maxAge = MAX(u.age)
|
||||
SORT ageGroup DESC
|
||||
RETURN {
|
||||
ageGroup,
|
||||
gender,
|
||||
numUsers,
|
||||
minAge,
|
||||
maxAge
|
||||
}
|
||||
```
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT ageGroup = FLOOR(u.age / 5) * 5,
|
||||
gender = u.gender
|
||||
AGGREGATE numUsers = LENGTH(1),
|
||||
minAge = MIN(u.age),
|
||||
maxAge = MAX(u.age)
|
||||
SORT ageGroup DESC
|
||||
RETURN {
|
||||
ageGroup,
|
||||
gender,
|
||||
numUsers,
|
||||
minAge,
|
||||
maxAge
|
||||
}
|
||||
|
||||
[
|
||||
{
|
||||
"ageGroup" : 35,
|
||||
"gender" : "f",
|
||||
"numUsers" : 2,
|
||||
"minAge" : 36,
|
||||
"maxAge" : 39,
|
||||
},
|
||||
{
|
||||
"ageGroup" : 35,
|
||||
"gender" : "m",
|
||||
"numUsers" : 2,
|
||||
"minAge" : 35,
|
||||
"maxAge" : 39,
|
||||
},
|
||||
```json
|
||||
[
|
||||
{
|
||||
"ageGroup": 35,
|
||||
"gender": "f",
|
||||
"numUsers": 2,
|
||||
"minAge": 36,
|
||||
"maxAge": 39,
|
||||
},
|
||||
{
|
||||
"ageGroup": 35,
|
||||
"gender": "m",
|
||||
"numUsers": 2,
|
||||
"minAge": 35,
|
||||
"maxAge": 39,
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
We have used the aggregate functions *LENGTH* here (it returns the length of a array).
|
||||
This is the equivalent to SQL's `SELECT g, COUNT(*) FROM ... GROUP BY g`. In addition to
|
||||
*LENGTH* AQL also provides *MAX*, *MIN*, *SUM* and *AVERAGE*, *VARIANCE_POPULATION*,
|
||||
We have used the aggregate functions *LENGTH* here (it returns the length of a array).
|
||||
This is the equivalent to SQL's `SELECT g, COUNT(*) FROM ... GROUP BY g`. In addition to
|
||||
*LENGTH* AQL also provides *MAX*, *MIN*, *SUM* and *AVERAGE*, *VARIANCE_POPULATION*,
|
||||
*VARIANCE_SAMPLE*, *STDDEV_POPULATION* and *STDDEV_SAMPLE* as basic aggregation functions.
|
||||
|
||||
In AQL all aggregation functions can be run on arrays only. If an aggregation function
|
||||
|
@ -265,38 +273,40 @@ Aggregation can also be performed after a *COLLECT* operation using other AQL co
|
|||
though performance-wise this is often inferior to using *COLLECT* with *AGGREGATE*.
|
||||
|
||||
The same query as before can be turned into a post-aggregation query as shown below. Note
|
||||
that this query will build and pass on all group values for all groups inside the variable
|
||||
that this query will build and pass on all group values for all groups inside the variable
|
||||
*g*, and perform the aggregation at the latest possible stage:
|
||||
|
||||
```js
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT ageGroup = FLOOR(u.age / 5) * 5,
|
||||
gender = u.gender INTO g
|
||||
SORT ageGroup DESC
|
||||
RETURN {
|
||||
ageGroup,
|
||||
gender,
|
||||
numUsers: LENGTH(g[*]),
|
||||
minAge: MIN(g[*].u.age),
|
||||
maxAge: MAX(g[*].u.age)
|
||||
}
|
||||
```
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT ageGroup = FLOOR(u.age / 5) * 5,
|
||||
gender = u.gender INTO g
|
||||
SORT ageGroup DESC
|
||||
RETURN {
|
||||
ageGroup,
|
||||
gender,
|
||||
numUsers : LENGTH(g[*]),
|
||||
minAge : MIN(g[*].u.age),
|
||||
maxAge : MAX(g[*].u.age)
|
||||
}
|
||||
|
||||
[
|
||||
{
|
||||
"ageGroup" : 35,
|
||||
"gender" : "f",
|
||||
"numUsers" : 2,
|
||||
"minAge" : 36,
|
||||
"maxAge" : 39,
|
||||
},
|
||||
{
|
||||
"ageGroup" : 35,
|
||||
"gender" : "m",
|
||||
"numUsers" : 2,
|
||||
"minAge" : 35,
|
||||
"maxAge" : 39,
|
||||
},
|
||||
```json
|
||||
[
|
||||
{
|
||||
"ageGroup": 35,
|
||||
"gender": "f",
|
||||
"numUsers": 2,
|
||||
"minAge": 36,
|
||||
"maxAge": 39,
|
||||
},
|
||||
{
|
||||
"ageGroup": 35,
|
||||
"gender": "m",
|
||||
"numUsers": 2,
|
||||
"minAge": 35,
|
||||
"maxAge": 39,
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
@ -308,60 +318,62 @@ the aggregation during the collect operation, at the earliest possible stage.
|
|||
!SUBSECTION Post-filtering aggregated data
|
||||
|
||||
To filter the results of a grouping or aggregation operation (i.e. something
|
||||
similar to *HAVING* in SQL), simply add another *FILTER* clause after the *COLLECT*
|
||||
statement.
|
||||
similar to *HAVING* in SQL), simply add another *FILTER* clause after the *COLLECT*
|
||||
statement.
|
||||
|
||||
For example, to get the 3 *ageGroup*s with the most users in them:
|
||||
|
||||
```js
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT ageGroup = FLOOR(u.age / 5) * 5 INTO group
|
||||
LET numUsers = LENGTH(group)
|
||||
FILTER numUsers > 2 /* group must contain at least 3 users in order to qualify */
|
||||
SORT numUsers DESC
|
||||
LIMIT 0, 3
|
||||
RETURN {
|
||||
"ageGroup": ageGroup,
|
||||
"numUsers": numUsers,
|
||||
"users": group[*].u.name
|
||||
}
|
||||
```
|
||||
FOR u IN users
|
||||
FILTER u.active == true
|
||||
COLLECT ageGroup = FLOOR(u.age / 5) * 5 INTO group
|
||||
LET numUsers = LENGTH(group)
|
||||
FILTER numUsers > 2 /* group must contain at least 3 users in order to qualify */
|
||||
SORT numUsers DESC
|
||||
LIMIT 0, 3
|
||||
RETURN {
|
||||
"ageGroup" : ageGroup,
|
||||
"numUsers" : numUsers,
|
||||
"users" : group[*].u.name
|
||||
}
|
||||
|
||||
[
|
||||
{
|
||||
"ageGroup" : 30,
|
||||
"numUsers" : 8,
|
||||
"users" : [
|
||||
"Abigail",
|
||||
"Madison",
|
||||
"Anthony",
|
||||
"Alexander",
|
||||
"Isabella",
|
||||
"Chloe",
|
||||
"Daniel",
|
||||
"Michael"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ageGroup" : 25,
|
||||
"numUsers" : 4,
|
||||
"users" : [
|
||||
"Mary",
|
||||
"Mariah",
|
||||
"Jim",
|
||||
"Diego"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ageGroup" : 35,
|
||||
"numUsers" : 4,
|
||||
"users" : [
|
||||
"Fred",
|
||||
"John",
|
||||
"Emma",
|
||||
"Sophia"
|
||||
]
|
||||
}
|
||||
```json
|
||||
[
|
||||
{
|
||||
"ageGroup": 30,
|
||||
"numUsers": 8,
|
||||
"users": [
|
||||
"Abigail",
|
||||
"Madison",
|
||||
"Anthony",
|
||||
"Alexander",
|
||||
"Isabella",
|
||||
"Chloe",
|
||||
"Daniel",
|
||||
"Michael"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ageGroup": 25,
|
||||
"numUsers": 4,
|
||||
"users": [
|
||||
"Mary",
|
||||
"Mariah",
|
||||
"Jim",
|
||||
"Diego"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ageGroup": 35,
|
||||
"numUsers": 4,
|
||||
"users": [
|
||||
"Fred",
|
||||
"John",
|
||||
"Emma",
|
||||
"Sophia"
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
|
|
@ -24,7 +24,9 @@ FOR u IN users
|
|||
"user" : u.name,
|
||||
"friendId" : f.thisUser
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"user" : "Abigail",
|
||||
|
@ -88,7 +90,9 @@ FOR u IN users
|
|||
RETURN f.thisUser
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"user" : "Abigail",
|
||||
|
@ -144,7 +148,9 @@ FOR u IN users
|
|||
RETURN u2.name
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"user" : "Abigail",
|
||||
|
@ -196,7 +202,9 @@ FOR user IN users
|
|||
)
|
||||
FILTER LENGTH(friendList) == 0
|
||||
RETURN { "user" : user.name }
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"user" : "Abigail"
|
||||
|
@ -217,12 +225,21 @@ Since we're free of schemata, there is by default no way to tell the format of t
|
|||
documents. So, if your documents don't contain an attribute, it defaults to
|
||||
null. We can however check our data for accuracy like this:
|
||||
|
||||
```
|
||||
```js
|
||||
RETURN LENGTH(FOR u IN users FILTER u.userId == null RETURN 1)
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
10000
|
||||
]
|
||||
```
|
||||
|
||||
```js
|
||||
RETURN LENGTH(FOR f IN relations FILTER f.friendOf == null RETURN 1)
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
10000
|
||||
]
|
||||
|
|
|
@ -8,7 +8,9 @@ To return three complete documents from collection *users*, the following query
|
|||
FOR u IN users
|
||||
LIMIT 0, 3
|
||||
RETURN u
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"_id" : "users/229886047207520",
|
||||
|
@ -61,7 +63,9 @@ FOR u IN users
|
|||
"name" : u.name
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"user" : {
|
||||
|
@ -99,7 +103,9 @@ FOR u IN users
|
|||
"age" : u.age,
|
||||
"name" : u.name
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"age" : 37,
|
||||
|
|
|
@ -14,9 +14,10 @@ Some of the following example queries are executed on a collection 'users' with
|
|||
Note that all documents created in any collections will automatically get the
|
||||
following server-generated attributes:
|
||||
|
||||
* *_id*: A unique id, consisting of [collection name](../Glossary/README.md#collection-name) and a server-side sequence value
|
||||
* *_key*: The server sequence value
|
||||
* *_rev*: The document's revision id
|
||||
- *_id*: A unique id, consisting of [collection name](../../Users/Appendix/Glossary.html#collection-name)
|
||||
and a server-side sequence value
|
||||
- *_key*: The server sequence value
|
||||
- *_rev*: The document's revision id
|
||||
|
||||
Whenever you run queries on the documents in collections, don't be surprised if
|
||||
these additional attributes are returned as well.
|
||||
|
@ -25,7 +26,7 @@ Please also note that with real-world data, you might want to create additional
|
|||
indexes on the data (left out here for brevity). Adding indexes on attributes that are
|
||||
used in *FILTER* statements may considerably speed up queries. Furthermore, instead of
|
||||
using attributes such as *id*, *from* and *to*, you might want to use the built-in
|
||||
*_id*, *_from* and *_to* attributes. Finally, [edge collection](../Glossary/README.md#edge-collection)s provide a nice way of
|
||||
*_id*, *_from* and *_to* attributes. Finally, [edge collection](../../Users/Appendix/Glossary.html#edge-collection)s provide a nice way of
|
||||
establishing references / links between documents. These features have been left out here
|
||||
for brevity as well.
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ An explain will throw an error if the given query is syntactically invalid. Othe
|
|||
return the execution plan and some information about what optimizations could be applied to
|
||||
the query. The query will not be executed.
|
||||
|
||||
Explaining a query can be achieved by calling the [HTTP REST API](../HttpAqlQuery/README.md).
|
||||
Explaining a query can be achieved by calling the [HTTP REST API](../../HTTP/AqlQuery/index.html).
|
||||
A query can also be explained from the ArangoShell using `ArangoStatement`'s `explain` method.
|
||||
|
||||
By default, the query optimizer will return what it considers to be the *optimal plan*. The
|
||||
|
@ -19,12 +19,12 @@ is an array of warnings that occurred during optimization or execution plan crea
|
|||
|
||||
Each plan in the result is an object with the following attributes:
|
||||
- *nodes*: the array of execution nodes of the plan. The list of available node types
|
||||
can be found [here](../Aql/Optimizer.md)
|
||||
can be found [here](Optimizer.md)
|
||||
- *estimatedCost*: the total estimated cost for the plan. If there are multiple
|
||||
plans, the optimizer will choose the plan with the lowest total cost.
|
||||
- *collections*: an array of collections used in the query
|
||||
- *rules*: an array of rules the optimizer applied. The list of rules can be
|
||||
found [here](../Aql/Optimizer.md)
|
||||
found [here](Optimizer.md)
|
||||
- *variables*: array of variables used in the query (note: this may contain
|
||||
internal variables created by the optimizer)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
!CHAPTER Parsing queries
|
||||
|
||||
Clients can use ArangoDB to check if a given AQL query is syntactically valid. ArangoDB provides
|
||||
an [HTTP REST API](../HttpAqlQuery/README.md) for this.
|
||||
an [HTTP REST API](../../HTTP/AqlQuery/index.html) for this.
|
||||
|
||||
A query can also be parsed from the ArangoShell using `ArangoStatement`'s `parse` method. The
|
||||
`parse` method will throw an exception if the query is syntactically invalid. Otherwise, it will
|
||||
|
|
|
@ -123,6 +123,6 @@ Documents in the *_aqlfunctions* collection (or any other system collection)
|
|||
should not be accessed directly, but only via the dedicated interfaces.
|
||||
|
||||
Keep in mind that system collections are excluded from dumps created with
|
||||
[arangodump](../HttpBulkImports/Arangodump.md) by default. To include AQL user
|
||||
[arangodump](../../Users/Administration/Arangodump.html) by default. To include AQL user
|
||||
functions in a dump, the dump needs to be started with the
|
||||
option *--include-system-collections true*.
|
||||
|
|
|
@ -10,7 +10,7 @@ var aqlfunctions = require("@arangodb/aql/functions");
|
|||
To register a function, the fully qualified function name plus the
|
||||
function code must be specified.
|
||||
|
||||
The [HTTP Interface](../HttpAqlUserFunctions/README.md) also offers User Functions management.
|
||||
The [HTTP Interface](../../HTTP/AqlUserFunctions/index.html) also offers User Functions management.
|
||||
|
||||
!SUBSECTION Registering an AQL user function
|
||||
|
||||
|
@ -24,7 +24,7 @@ the string evaluates to a JavaScript function definition.
|
|||
|
||||
If a function identified by *name* already exists, the previous function
|
||||
definition will be updated. Please also make sure that the function code
|
||||
does not violate the [Conventions](../AqlExtending/Conventions.md) for AQL
|
||||
does not violate the [Conventions](Conventions.md) for AQL
|
||||
functions.
|
||||
|
||||
The *isDeterministic* attribute can be used to specify whether the
|
||||
|
|
|
@ -6,10 +6,10 @@ fully-featured programming language.
|
|||
To add missing functionality or to simplify queries, users
|
||||
may add their own functions to AQL in the selected database.
|
||||
These functions can be written in JavaScript, and must be
|
||||
registered via the API; see [Registering Functions](../AqlExtending/Functions.md).
|
||||
registered via the API; see [Registering Functions](Functions.md).
|
||||
|
||||
In order to avoid conflicts with existing or future built-in
|
||||
function names, all user functions must be put into separate
|
||||
namespaces. Invoking a user functions is then possible by referring
|
||||
to the fully-qualified function name, which includes the namespace,
|
||||
too; see [Conventions](../AqlExtending/Conventions.md).
|
||||
too; see [Conventions](Conventions.md).
|
||||
|
|
|
@ -39,7 +39,7 @@ You are free to store age determinations of specimens, incomplete or fuzzy dates
|
|||
the like in different, more appropriate ways of course. AQL's date functions will
|
||||
most certainly not be of any help for such dates, but you can still use language
|
||||
constructs like [SORT](../Operations/Sort.md) (which also supports sorting of arrays)
|
||||
and [indexes](../Indexing/README.md) like skiplists.
|
||||
and [indexes](../../Users/Indexing/index.html) like skiplists.
|
||||
|
||||
!SECTION Current date and time
|
||||
|
||||
|
@ -623,7 +623,7 @@ There are two recommended ways to store timestamps in ArangoDB:
|
|||
The sort order of both is identical due to the sort properties of ISO date strings.
|
||||
You can't mix both types, numbers and strings, in a single attribute however.
|
||||
|
||||
You can use [skiplist indices](../IndexHandling/Skiplist.md) with both date types.
|
||||
You can use [skiplist indices](../../Users/Indexing/Skiplist.html) with both date types.
|
||||
When chosing string representations, you can work with string comparisons (less than,
|
||||
greater than etc.) to express time ranges in your queries while still utilizing
|
||||
skiplist indices:
|
||||
|
|
|
@ -79,7 +79,7 @@ HAS( { }, "name" ) // false
|
|||
`IS_SAME_COLLECTION(collectionName, documentHandle) → bool`
|
||||
|
||||
collection id as the collection specified in *collection*. *document* can either be
|
||||
a [document handle](../Glossary/README.md#document-handle) string, or a document with
|
||||
a [document handle](../../Users/Appendix/Glossary.html#document-handle) string, or a document with
|
||||
an *_id* attribute. The function does not validate whether the collection actually
|
||||
contains the specified document, but only compares the name of the specified collection
|
||||
with the collection name part of the specified document.
|
||||
|
@ -283,11 +283,11 @@ MERGE_RECURSIVE(
|
|||
|
||||
`PARSE_IDENTIFIER(documentHandle) → parts`
|
||||
|
||||
Parse a [document handle](../Glossary/README.md#document-handle) and return its
|
||||
Parse a [document handle](../../Users/Appendix/Glossary.html#document-handle) and return its
|
||||
individual parts a separate attributes.
|
||||
|
||||
This function can be used to easily determine the
|
||||
[collection name](../Glossary/README.md#collection-name) and key of a given document.
|
||||
[collection name](../../Users/Appendix/Glossary.html#collection-name) and key of a given document.
|
||||
|
||||
- **documentHandle** (string|object): a document identifier string (e.g. *_users/1234*)
|
||||
or a regular document from a collection. Passing either a non-string or a non-document
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
!CHAPTER Fulltext functions
|
||||
|
||||
AQL offers the following functions to filter data based on
|
||||
[fulltext indexes](../Indexing/Fulltext.md):
|
||||
[fulltext indexes](../../Users/Indexing/Fulltext.html):
|
||||
|
||||
!SUBSECTION FULLTEXT()
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
!SECTION Geo index functions
|
||||
|
||||
AQL offers the following functions to filter data based on
|
||||
[geo indexes](../Indexing/Geo.md). These functions require the collection to have at
|
||||
[geo indexes](../../Users/Indexing/Geo.html). These functions require the collection to have at
|
||||
least one geo index. If no geo index can be found, calling this function will fail
|
||||
with an error.
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ alternatives is a document.
|
|||
!SUBSECTION Ternary operator
|
||||
|
||||
For conditional evaluation, check out the
|
||||
[ternary operator](../Aql/Operators.md#ternary-operator).
|
||||
[ternary operator](../Operators.md#ternary-operator).
|
||||
|
||||
!SECTION Database functions
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ Since ArangoDB 1.3, it is possible to extend AQL with user-defined functions.
|
|||
These functions need to be written in JavaScript, and be registered before usage
|
||||
in a query.
|
||||
|
||||
Please refer to [Extending AQL](../AqlExtending/README.md) for more details on this.
|
||||
Please refer to [Extending AQL](../Extending/index.html) for more details on this.
|
||||
|
||||
By default, any function used in an AQL query will be sought in the built-in
|
||||
function namespace *_aql*. This is the default namespace that contains all AQL
|
||||
|
|
|
@ -24,7 +24,7 @@ letter, digit or the underscore symbol.
|
|||
|
||||
Bind variables represent a value like a string, and must not be put in quotes.
|
||||
If you need to do string processing (concatenation, etc.) in the AQL query, you need
|
||||
[to use string functions to do so](../Aql/StringFunctions.md):
|
||||
[to use string functions to do so](../Functions/String.md):
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.id == CONCAT('prefix', @id, 'suffix') && u.name == @name
|
||||
|
@ -40,5 +40,8 @@ when using the bind parameter in a query, two *@* symbols must be used).
|
|||
RETURN u
|
||||
|
||||
|
||||
Specific information about parameters binding can also be found in [Aql With Web Interface](AqlWithWebInterface.md) and [Aql With Arangosh](AqlWithArangosh.md), and [HTTP Interface for AQL Queries](../HttpAqlQuery/README.md)
|
||||
Specific information about parameters binding can also be found in
|
||||
[Aql With Web Interface](../Invocation/WithWebInterface.md) and
|
||||
[Aql With Arangosh](../Invocation/WithArangosh.md), and
|
||||
[HTTP Interface for AQL Queries](../../HTTP/AqlQuery/index.html)
|
||||
|
||||
|
|
|
@ -26,6 +26,6 @@ examples that will cause run-time errors are:
|
|||
includes unary (logical not/negation), binary (logical and, logical or), and
|
||||
the ternary operators
|
||||
|
||||
Please refer to the [Arango Errors](../ErrorCodes/README.md) page for a list of error codes and
|
||||
meanings.
|
||||
Please refer to the [Arango Errors](../../Users/Appendix/ErrorCodes.html) page
|
||||
for a list of error codes and meanings.
|
||||
|
||||
|
|
|
@ -11,34 +11,47 @@ For example, when returning data from a collection with inhomogeneous documents
|
|||
without modification, the result values will as well have an inhomogeneous
|
||||
structure. Each result value itself is a document:
|
||||
|
||||
FOR u IN users
|
||||
RETURN u
|
||||
|
||||
[ { "id" : 1, "name" : "John", "active" : false },
|
||||
{ "age" : 32, "id" : 2, "name" : "Vanessa" },
|
||||
{ "friends" : [ "John", "Vanessa" ], "id" : 3, "name" : "Amy" } ]
|
||||
```js
|
||||
FOR u IN users
|
||||
RETURN u
|
||||
```
|
||||
|
||||
```json
|
||||
[ { "id": 1, "name": "John", "active": false },
|
||||
{ "age": 32, "id": 2, "name": "Vanessa" },
|
||||
{ "friends": [ "John", "Vanessa" ], "id": 3, "name": "Amy" } ]
|
||||
```
|
||||
|
||||
However, if a fixed set of attributes from the collection is queried, then the
|
||||
query result values will have a homogeneous structure. Each result value is
|
||||
still a document:
|
||||
|
||||
FOR u IN users
|
||||
RETURN { "id" : u.id, "name" : u.name }
|
||||
|
||||
[ { "id" : 1, "name" : "John" },
|
||||
{ "id" : 2, "name" : "Vanessa" },
|
||||
{ "id" : 3, "name" : "Amy" } ]
|
||||
```js
|
||||
FOR u IN users
|
||||
RETURN { "id": u.id, "name": u.name }
|
||||
```
|
||||
|
||||
```json
|
||||
[ { "id": 1, "name": "John" },
|
||||
{ "id": 2, "name": "Vanessa" },
|
||||
{ "id": 3, "name": "Amy" } ]
|
||||
```
|
||||
|
||||
It is also possible to query just scalar values. In this case, the result set
|
||||
is an array of scalars, and each result value is a scalar value:
|
||||
|
||||
FOR u IN users
|
||||
RETURN u.id
|
||||
|
||||
[ 1, 2, 3 ]
|
||||
```js
|
||||
FOR u IN users
|
||||
RETURN u.id
|
||||
```
|
||||
|
||||
```json
|
||||
[ 1, 2, 3 ]
|
||||
```
|
||||
|
||||
If a query does not produce any results because no matching data can be
|
||||
found, it will produce an empty result array:
|
||||
|
||||
[ ]
|
||||
|
||||
```json
|
||||
[ ]
|
||||
```
|
||||
|
|
|
@ -156,8 +156,8 @@ The example can alternatively written as:
|
|||
Collection names can be used in queries as they are. If a collection happens to
|
||||
have the same name as a keyword, the name must be enclosed in backticks.
|
||||
|
||||
Please refer to the [Naming Conventions in ArangoDB](../NamingConventions/CollectionNames.md) about collection naming
|
||||
conventions.
|
||||
Please refer to the [Naming Conventions in ArangoDB](../../Users/DataModeling/NamingConventions/CollectionNames.html)
|
||||
about collection naming conventions.
|
||||
|
||||
!SUBSUBSECTION Attribute names
|
||||
|
||||
|
@ -166,8 +166,8 @@ attribute name must be used. This is because multiple collections with ambiguous
|
|||
attribute names may be used in a query. To avoid any ambiguity, it is not
|
||||
allowed to refer to an unqualified attribute name.
|
||||
|
||||
Please refer to the [Naming Conventions in ArangoDB](../NamingConventions/AttributeNames.md) for more information about the
|
||||
attribute naming conventions.
|
||||
Please refer to the [Naming Conventions in ArangoDB](../../Users/DataModeling/NamingConventions/AttributeNames.html)
|
||||
for more information about the attribute naming conventions.
|
||||
|
||||
FOR u IN users
|
||||
FOR f IN friends
|
||||
|
|
|
@ -9,7 +9,7 @@ data values if the operands have the same data types.
|
|||
|
||||
The following type order is used when comparing data types:
|
||||
|
||||
null < bool < number < string < array < object / document
|
||||
null < bool < number < string < array/list < object/document
|
||||
|
||||
This means *null* is the smallest type in AQL and *document* is the type with
|
||||
the highest order. If the compared operands have a different type, then the
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
AQL has the following functions to traverse loosely-structured graphs consisting of
|
||||
an edge collection and plus the vertices connected by it. If you have created a graph
|
||||
using the general-graph module you may want to use its more specific [Graph operations](../Aql/GraphOperations.md)
|
||||
using the general-graph module you may want to use its more specific [Graph operations](Operations.md)
|
||||
instead.
|
||||
|
||||
|
||||
|
@ -74,8 +74,8 @@ with the option *includeVertices* set to true.
|
|||
|
||||
!SECTION General Purpose Traversals
|
||||
|
||||
General purpose traversals with its extendability by visitor functions offer more possibilities over the newer [AQL graph traversals](../Aql/GraphTraversals.md),
|
||||
however unless you need some of these features you should [prefer AQL graph traversals](../Aql/GraphTraversals.md).
|
||||
General purpose traversals with its extendability by visitor functions offer more possibilities over the newer [AQL graph traversals](Traversals.md),
|
||||
however unless you need some of these features you should [prefer AQL graph traversals](Traversals.md).
|
||||
|
||||
!SUBSECTION Traversal
|
||||
*TRAVERSAL(vertexcollection, edgecollection, startVertex, direction, options)*:
|
||||
|
@ -516,7 +516,7 @@ path is a document consisting of the following attributes:
|
|||
RETURN p.vertices[*].name
|
||||
|
||||
!SECTION Graph consistency
|
||||
When [using the graph management functions to remove vertices](../GeneralGraphs/Management.md#remove-a-vertex)
|
||||
When [using the graph management functions to remove vertices](Management.md#remove-a-vertex)
|
||||
you have the guaranty that all referencing edges are also removed.
|
||||
However, if you use document features alone to remove vertices, no edge collections will be adjusted.
|
||||
This results in an edge with its `_from` or `_to` attribute referring to vanished vertices.
|
||||
|
@ -532,7 +532,7 @@ In order to keep the result set consistent between *includeData* enabled or disa
|
|||
|
||||
When using any of AQL's general purpose traversal functions, please make sure that the graph
|
||||
does not contain cycles, or that you at least specify some maximum depth or uniqueness
|
||||
criteria for a traversal. In contrast [AQL graph traversals](../Aql/GraphTraversals.md) won't trap on cycles.
|
||||
criteria for a traversal. In contrast [AQL graph traversals](Traversals.md) won't trap on cycles.
|
||||
|
||||
If no bounds are set, a traversal may run into an endless loop in a cyclic graph or sub-graph.
|
||||
Even in a non-cyclic graph, traversing far into the graph may consume a lot of processing
|
||||
|
|
|
@ -24,9 +24,9 @@ the amount of vertices in the graph, *x* the amount of start vertices and *y* th
|
|||
target vertices. Hence a suggestion may be to use Dijkstra when x\*y < n and the functions supports choosing your algorithm.
|
||||
|
||||
!SUBSECTION Example Graph
|
||||
All examples in this chapter will use [this simple city graph](../Graphs/README.md#the-city-graph):
|
||||
All examples in this chapter will use [this simple city graph](../../Users/Graphs/index.html#the-city-graph):
|
||||
|
||||

|
||||

|
||||
|
||||
!SUBSECTION Edges and Vertices related functions
|
||||
|
||||
|
@ -576,7 +576,7 @@ The complexity of this function strongly depends on the usage.
|
|||
- *connectName*: The result attribute which
|
||||
contains the connection.
|
||||
- *options* (optional): An object containing options, see
|
||||
[Graph Traversals](../Aql/GraphOperations.md#graphtraversal):
|
||||
[Graph Traversals](#graphtraversal):
|
||||
|
||||
|
||||
**Examples**
|
||||
|
@ -1092,9 +1092,8 @@ outbound paths.
|
|||
|
||||
`GRAPH_RADIUS (graphName, options)`
|
||||
|
||||
*The GRAPH\_RADIUS function returns the
|
||||
[radius](http://en.wikipedia.org/wiki/Eccentricity_%28graph_theory%29)
|
||||
of a graph.*
|
||||
The GRAPH_RADIUS function returns the
|
||||
[radius](http://en.wikipedia.org/wiki/Eccentricity_%28graph_theory%29) of a graph.
|
||||
|
||||
The complexity of the function is described
|
||||
[here](#the-complexity-of-the-shortest-path-algorithms).
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
!CHAPTER Graphs in AQL
|
||||
|
||||
As you already [read about graphs in ArangoDB](../Graphs/README.md) you can have several views on graphs.
|
||||
As you already [read about graphs in ArangoDB](../../Users/Graphs/index.html) you can have several views on graphs.
|
||||
There are also several ways to work with graphs in AQL.
|
||||
You can use named graphs where ArangoDB manages the collections involved in one graph.
|
||||
You can also use graph functions on a combination of document and edge collections.
|
||||
named graphs are defined though the [graph-module](../GeneralGraphs/README.md), that contains the name of the graph, and the vertex and edge collections involved.
|
||||
named graphs are defined though the [graph-module](../../Users/Graphs/GeneralGraphs/index.html), that contains the name of the graph, and the vertex and edge collections involved.
|
||||
Since the management functions are layered on top of simple sets of document and edge collections, you can also use regular AQL functions to work with them.
|
||||
|
||||
In AQL you can reach several graphing functions:
|
||||
* [AQL Traversals](GraphTraversals.md) is making full use of optimisations and therefore best performance is to be expected. It can work on named graphs and loosely coupled collection sets (aka anonymous graphs). You can use AQL filter conditions on traversals.
|
||||
* [Named graph Operations](GraphOperations.md) work on named graphs; offer a versatile range of parameters.
|
||||
* [Other graph functions](GraphFunctions.md) work on single edge collection (which may also be part of named graphs).
|
||||
* [AQL Traversals](Traversals.md) is making full use of optimisations and therefore best performance is to be expected. It can work on named graphs and loosely coupled collection sets (aka anonymous graphs). You can use AQL filter conditions on traversals.
|
||||
* [Named graph Operations](Operations.md) work on named graphs; offer a versatile range of parameters.
|
||||
* [Other graph functions](Functions.md) work on single edge collection (which may also be part of named graphs).
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ For all vertices that where visited during this process in the range between *mi
|
|||
Let's take a look at a simple example to explain how it works.
|
||||
This is the graph that we are going to traverse:
|
||||
|
||||

|
||||

|
||||
|
||||
Now we use the following parameters for our query:
|
||||
|
||||
|
@ -27,36 +27,36 @@ Now we use the following parameters for our query:
|
|||
3. We use a *max-depth* of 2.
|
||||
4. We follow only *outbound* direction of edges
|
||||
|
||||

|
||||

|
||||
|
||||
Now it walks to one of the direct neighbors of **A**, say **B** (NOTE: ordering is not guaranteed):
|
||||
|
||||

|
||||

|
||||
|
||||
The query will remember the state (red circle) and will emit the first result **A** -> **B** (black box).
|
||||
This will also prevent the traverser to be trapped in cycles.
|
||||
Now again it will visit one of the direct neighbors of **B**, say **E**:
|
||||
|
||||

|
||||

|
||||
|
||||
We have limited the query with a *max-depth* of *2* then it will not pick any neighbor of **E** as the path from **A** to **E** already requires *2* steps.
|
||||
Instead we will go back one level to **B** and continue with any other direct neighbor there:
|
||||
|
||||

|
||||

|
||||
|
||||
Again after we produced this result we will step back to **B**.
|
||||
But there is no neighbor of **B** left that we have not yet visited.
|
||||
Hence we go another step back to **A** and continue with any other neighbor there.
|
||||
|
||||

|
||||

|
||||
|
||||
And identical to the iterations before we will visit **H**:
|
||||
|
||||

|
||||

|
||||
|
||||
And **J**:
|
||||
|
||||

|
||||

|
||||
|
||||
And after these steps there is no further result left.
|
||||
So all together this query has returned the following paths:
|
||||
|
@ -72,7 +72,7 @@ So all together this query has returned the following paths:
|
|||
!SUBSECTION Syntax
|
||||
|
||||
Now let's see how we can write a query that follows this schema.
|
||||
You have two options here, you can either use a named graph (see [the graphs chapter](../Graphs/README.md) on how to create it) or anonymous graphs.
|
||||
You have two options here, you can either use a named graph (see [the graphs chapter](index.html) on how to create it) or anonymous graphs.
|
||||
|
||||
!SUBSUBSECTION Working on named graphs:
|
||||
|
||||
|
@ -81,18 +81,18 @@ You have two options here, you can either use a named graph (see [the graphs cha
|
|||
`OUTBOUND|INBOUND|ANY` startVertex
|
||||
`GRAPH` graphName
|
||||
|
||||
- `FOR` - emits up to three variables:
|
||||
- **vertex**: the current vertex in a traversal
|
||||
- **edge**: *(optional)* the current edge in a traversal
|
||||
- **path**: *(optional, requires edge to be present)* an object representing the current path with two members:
|
||||
- `vertices`: an array of all vertices on this path.
|
||||
- `edges`: an array of all edges on this path.
|
||||
- `IN` `MIN`..`MAX` `OUTBOUND` startVertex `GRAPH` graphName
|
||||
- `OUTBOUND|INBOUND|ANY` traversal will be done for outbound / inbound / inbound+outbound pointing edges
|
||||
- **startVertex**: one vertex where the traversal will originate from, this can be specified in the form of an id string or in the form of a document with the attribute `_id`. All other values will lead to a warning and an empty result. If the specified id does not exist, the result is empty as well and there is no warning.
|
||||
- **graphName**: the name identifying the named graph. It's vertex and edge collections will be looked up.
|
||||
- `MIN`: edges and vertices returned by this query will start at the traversal depth of `MIN` (thus edges and vertices below will not be returned). If not specified, defaults to `1`, which is the minimal possible value.
|
||||
- `MAX`: up to `MAX` length paths are traversed. If omitted in the query, `MAX` equals `MIN`. Thus only the vertices and edges in the range of `MIN` are returned.
|
||||
- `FOR` - emits up to three variables:
|
||||
- **vertex**: the current vertex in a traversal
|
||||
- **edge**: *(optional)* the current edge in a traversal
|
||||
- **path**: *(optional, requires edge to be present)* an object representing the current path with two members:
|
||||
- `vertices`: an array of all vertices on this path.
|
||||
- `edges`: an array of all edges on this path.
|
||||
- `IN` `MIN`..`MAX` `OUTBOUND` startVertex `GRAPH` graphName
|
||||
- `OUTBOUND|INBOUND|ANY` traversal will be done for outbound / inbound / inbound+outbound pointing edges
|
||||
- **startVertex**: one vertex where the traversal will originate from, this can be specified in the form of an id string or in the form of a document with the attribute `_id`. All other values will lead to a warning and an empty result. If the specified id does not exist, the result is empty as well and there is no warning.
|
||||
- **graphName**: the name identifying the named graph. It's vertex and edge collections will be looked up.
|
||||
- `MIN`: edges and vertices returned by this query will start at the traversal depth of `MIN` (thus edges and vertices below will not be returned). If not specified, defaults to `1`, which is the minimal possible value.
|
||||
- `MAX`: up to `MAX` length paths are traversed. If omitted in the query, `MAX` equals `MIN`. Thus only the vertices and edges in the range of `MIN` are returned.
|
||||
|
||||
!SUBSUBSECTION Working on collection sets:
|
||||
|
||||
|
@ -171,7 +171,7 @@ This is because for all results in depth `1` the second edge does not exist and
|
|||
|
||||
!SUBSUBSECTION Examples
|
||||
We will create a simple symmetric traversal demonstration graph:
|
||||

|
||||

|
||||
|
||||
@startDocuBlockInline GRAPHTRAV_01_create_graph
|
||||
@EXAMPLE_ARANGOSH_OUTPUT{GRAPHTRAV_01_create_graph}
|
||||
|
@ -260,7 +260,8 @@ Due to this we will see duplicate nodes in the result.
|
|||
|
||||
!SUBSUBSECTION Use the AQL explainer for optimizations
|
||||
|
||||
Now lets have a look what the optimizer does behind the curtains and inspect traversal queries using [the explainer](Optimizer.md):
|
||||
Now lets have a look what the optimizer does behind the curtains and inspect traversal queries using
|
||||
[the explainer](../ExecutionAndPerformance/Optimizer.md):
|
||||
|
||||
|
||||
@startDocuBlockInline GRAPHTRAV_07_traverse_7
|
||||
|
@ -284,6 +285,6 @@ And finally clean it up again:
|
|||
@endDocuBlock GRAPHTRAV_99_drop_graph
|
||||
|
||||
|
||||
If this traversal is not powerful enough for your needs, so you cannot describe your conditions as AQL filter statements you might want to look at [manually crafted traverser](../Traversals/README.md).
|
||||
If this traversal is not powerful enough for your needs, so you cannot describe your conditions as AQL filter statements you might want to look at [manually crafted traverser](../../Users/Graphs/Traversals/index.html).
|
||||
|
||||
[See here for more traversal examples](../AqlExamples/CombiningGraphTraversals.md).
|
||||
[See here for more traversal examples](../Examples/CombiningGraphTraversals.md).
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
!CHAPTER How to invoke AQL
|
||||
|
||||
You can run AQL queries from your application via the HTTP REST API. The full
|
||||
API description is available at [HTTP Interface for AQL Query Cursors](../HttpAqlQueryCursor/README.md).
|
||||
API description is available at [HTTP Interface for AQL Query Cursors](../../HTTP/AqlQueryCursor/index.html).
|
||||
|
||||
The ArangoDB Web Interface has a [specific tab for AQL queries execution](AqlWithWebInterface.md).
|
||||
The ArangoDB Web Interface has a [specific tab for AQL queries execution](../Invocation/WithWebInterface.md).
|
||||
|
||||
You can run [AQL queries from the ArangoDB Shell](AqlWithArangosh.md) with the *_query* and *_createStatement* methods of the *db* object.
|
||||
You can run [AQL queries from the ArangoDB Shell](../Invocation/WithArangosh.md) with the *_query* and *_createStatement* methods of the *db* object.
|
||||
This chapter also describes how to use bind parameters, statistics, counting and cursors with arangosh.
|
||||
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ It is always possible to retrieve statistics for a query with the *getExtra* met
|
|||
@END_EXAMPLE_ARANGOSH_OUTPUT
|
||||
@endDocuBlock 03_workWithAQL_getExtra
|
||||
|
||||
The meaning of the statistics values is described in [Execution statistics](QueryStatistics.md).
|
||||
The meaning of the statistics values is described in [Execution statistics](../ExecutionAndPerformance/QueryStatistics.md).
|
||||
You also will find warnings in here; If you're designing queries on the shell be sure to also look at it.
|
||||
|
||||
!SUBSECTION with _createStatement (ArangoStatement)
|
||||
|
|
|
@ -12,18 +12,22 @@ They are defined as JSON values, the same format that is used for bind parameter
|
|||
|
||||
Here is an example:
|
||||
|
||||
for doc in @@collection
|
||||
FILTER CONTAINS(LOWER(doc.author), @search, false)
|
||||
return {"name":doc.name, "descr": doc.description, "author":doc.author}
|
||||
```js
|
||||
FOR doc IN @@collection
|
||||
FILTER CONTAINS(LOWER(doc.author), @search, false)
|
||||
RETURN { "name": doc.name, "descr": doc.description, "author": doc.author }
|
||||
```
|
||||
|
||||
Bind parameter:
|
||||
|
||||
{
|
||||
"@collection":"_apps",
|
||||
"search":"arango"
|
||||
}
|
||||
```js
|
||||
{
|
||||
"@collection": "_apps",
|
||||
"search": "arango"
|
||||
}
|
||||
```
|
||||
|
||||
An overview of Bind Parameters may be found in [Aql Fundamentals](BindParameters.md).
|
||||
An overview of Bind Parameters may be found in [Aql Fundamentals](../Fundamentals/BindParameters.md).
|
||||
|
||||
Queries can also be saved in the AQL editor along with their bind parameter values for later reuse. This data is stored in the user profile in the current database (in the *_users* system table).
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ In the above example, will be included in the result all array elements from *us
|
|||
an attribute *active* with value *true* and that have an attribute *age* with a
|
||||
value less than *39* (including *null* ones). All other elements from *users*
|
||||
will be skipped and not be included in the result produced by *RETURN*.
|
||||
You may refer to the chapter [Accessing Data from Collections](../Aql/DocumentData.md) for
|
||||
You may refer to the chapter [Accessing Data from Collections](../Fundamentals/DocumentData.md) for
|
||||
a description of the impact of non-existent or null attributes.
|
||||
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ There also is a special case for graph traversals:
|
|||
FOR vertex-variable-name, edge-variable-name, path-variable-name IN traversal-expression
|
||||
```
|
||||
|
||||
For this special case see [the graph traversals chapter](../Aql/GraphTraversals.md).
|
||||
For this special case see [the graph traversals chapter](../Graphs/Traversals.md).
|
||||
For all other cases read on:
|
||||
|
||||
Each array element returned by *expression* is visited exactly once. It is
|
||||
|
|
|
@ -5,7 +5,7 @@ single server, an insert operation is executed transactionally in an all-or-noth
|
|||
fashion. For sharded collections, the entire insert operation is not transactional.
|
||||
|
||||
Each *INSERT* operation is restricted to a single collection, and the
|
||||
[collection name](../Glossary/README.md#collection-name) must not be dynamic.
|
||||
[collection name](../../Users/Appendix/Glossary.html#collection-name) must not be dynamic.
|
||||
Only a single *INSERT* statement per collection is allowed per AQL query, and
|
||||
it cannot be followed by read operations that access the same collection, by
|
||||
traversal operations, or AQL functions that can read documents.
|
||||
|
@ -29,7 +29,7 @@ FOR i IN 1..100
|
|||
INSERT { value: i } IN numbers
|
||||
```
|
||||
|
||||
When inserting into an [edge collection](../Glossary/README.md#edge-collection), it is mandatory to specify the attributes
|
||||
When inserting into an [edge collection](../../Users/Appendix/Glossary.html#edge-collection), it is mandatory to specify the attributes
|
||||
*_from* and *_to* in document:
|
||||
|
||||
```
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
The following high-level operations are described here after:
|
||||
|
||||
* [FOR](../AqlOperations/For.md) : to iterate over all elements of an array.
|
||||
* [RETURN](../AqlOperations/Return.md) : to produce the result of a query.
|
||||
* [FILTER](../AqlOperations/Filter.md) : to restrict the results to elements that match an arbitrary logical condition.
|
||||
* [SORT](../AqlOperations/Sort.md) : to force a sort of the array of already produced intermediate results.
|
||||
* [LIMIT](../AqlOperations/Limit.md) : to reduce the number of elements in the result to at most the specified number.
|
||||
* [LET](../AqlOperations/Let.md) : to assign an arbitrary value to a variable.
|
||||
* [COLLECT](../AqlOperations/Collect.md) : to group an array by one or multiple group criteria.
|
||||
* [REMOVE](../AqlOperations/Remove.md) : to remove documents from a collection.
|
||||
* [UPDATE](../AqlOperations/Update.md) : to partially update documents in a collection.
|
||||
* [REPLACE](../AqlOperations/Replace.md) : to completely replace documents in a collection.
|
||||
* [INSERT](../AqlOperations/Insert.md) : to insert new documents into a collection.
|
||||
* [UPSERT](../AqlOperations/Upsert.md) : to update an existing document, or create it in the case it does not exist.
|
||||
* [FOR](For.md) : to iterate over all elements of an array.
|
||||
* [RETURN](Return.md) : to produce the result of a query.
|
||||
* [FILTER](Filter.md) : to restrict the results to elements that match an arbitrary logical condition.
|
||||
* [SORT](Sort.md) : to force a sort of the array of already produced intermediate results.
|
||||
* [LIMIT](Limit.md) : to reduce the number of elements in the result to at most the specified number.
|
||||
* [LET](Let.md) : to assign an arbitrary value to a variable.
|
||||
* [COLLECT](Collect.md) : to group an array by one or multiple group criteria.
|
||||
* [REMOVE](Remove.md) : to remove documents from a collection.
|
||||
* [UPDATE](Update.md) : to partially update documents in a collection.
|
||||
* [REPLACE](Replace.md) : to completely replace documents in a collection.
|
||||
* [INSERT](Insert.md) : to insert new documents into a collection.
|
||||
* [UPSERT](Upsert.md) : to update an existing document, or create it in the case it does not exist.
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ all-or-nothing fashion. For sharded collections, the entire remove operation
|
|||
is not transactional.
|
||||
|
||||
Each *REMOVE* operation is restricted to a single collection, and the
|
||||
[collection name](../Glossary/README.md#collection-name) must not be dynamic.
|
||||
[collection name](../../Users/Appendix/Glossary.html#collection-name) must not be dynamic.
|
||||
Only a single *REMOVE* statement per collection is allowed per AQL query, and
|
||||
it cannot be followed by read operations that access the same collection, by
|
||||
traversal operations, or AQL functions that can read documents.
|
||||
|
@ -20,7 +20,8 @@ REMOVE key-expression IN collection options
|
|||
|
||||
*collection* must contain the name of the collection to remove the documents
|
||||
from. *key-expression* must be an expression that contains the document identification.
|
||||
This can either be a string (which must then contain the [document key](../Glossary/README.md#document-key)) or a
|
||||
This can either be a string (which must then contain the
|
||||
[document key](../../Users/Appendix/Glossary.html#document-key)) or a
|
||||
document, which must contain a *_key* attribute.
|
||||
|
||||
The following queries are thus equivalent:
|
||||
|
|
|
@ -5,7 +5,7 @@ single server, the replace operation is executed transactionally in an all-or-no
|
|||
fashion. For sharded collections, the entire replace operation is not transactional.
|
||||
|
||||
Each *REPLACE* operation is restricted to a single collection, and the
|
||||
[collection name](../Glossary/README.md#collection-name) must not be dynamic.
|
||||
[collection name](../../Users/Appendix/Glossary.html#collection-name) must not be dynamic.
|
||||
Only a single *REPLACE* statement per collection is allowed per AQL query, and
|
||||
it cannot be followed by read operations that access the same collection, by
|
||||
traversal operations, or AQL functions that can read documents.
|
||||
|
|
|
@ -5,7 +5,7 @@ single server, updates are executed transactionally in an all-or-nothing fashion
|
|||
For sharded collections, the entire update operation is not transactional.
|
||||
|
||||
Each *UPDATE* operation is restricted to a single collection, and the
|
||||
[collection name](../Glossary/README.md#collection-name) must not be dynamic.
|
||||
[collection name](../../Users/Appendix/Glossary.html#collection-name) must not be dynamic.
|
||||
Only a single *UPDATE* statement per collection is allowed per AQL query, and
|
||||
it cannot be followed by read operations that access the same collection, by
|
||||
traversal operations, or AQL functions that can read documents.
|
||||
|
|
|
@ -6,7 +6,7 @@ On a single server, upserts are executed transactionally in an all-or-nothing fa
|
|||
For sharded collections, the entire update operation is not transactional.
|
||||
|
||||
Each *UPSERT* operation is restricted to a single collection, and the
|
||||
[collection name](../Glossary/README.md#collection-name) must not be dynamic.
|
||||
[collection name](../../Users/Appendix/Glossary.html#collection-name) must not be dynamic.
|
||||
Only a single *UPSERT* statement per collection is allowed per AQL query, and
|
||||
it cannot be followed by read operations that access the same collection, by
|
||||
traversal operations, or AQL functions that can read documents.
|
||||
|
|
|
@ -264,7 +264,8 @@ will produce the following result:
|
|||
|
||||
!SUBSUBSECTION Array operators
|
||||
|
||||
AQL provides [array operators](ArrayOperators.md) <i>[\*]</i> for array variable expansion and <i>[\*\*]</i> for array contraction.
|
||||
AQL provides [array operators](Advanced/ArrayOperators.md) <i>[\*]</i> for
|
||||
array variable expansion and <i>[\*\*]</i> for array contraction.
|
||||
|
||||
|
||||
!SUBSUBSECTION Operator precedence
|
||||
|
|
|
@ -26,5 +26,5 @@ The syntax of AQL queries is different to SQL, even if some keywords overlap.
|
|||
Nevertheless, AQL should be easy to understand for anyone with an SQL background.
|
||||
|
||||
For some example queries, please refer to the pages [Data Modification Queries](DataModification.md) and
|
||||
[Usual query patterns](../AqlExamples/README.md).
|
||||
[Usual query patterns](Examples/README.md).
|
||||
|
||||
|
|
Loading…
Reference in New Issue