1
0
Fork 0

Implement dynamic examples for invoking AQL tutorial

This commit is contained in:
Willi Goesgens 2015-08-06 17:52:57 +02:00 committed by Michael Hackstein
parent 500371d658
commit b9a25e02c0
2 changed files with 152 additions and 189 deletions

View File

@ -10,31 +10,36 @@ of the *db* object. This will run the specified query in the context of the curr
selected database and return the query results in a cursor. The results of the cursor
can be printed using its *toArray* method:
arangosh> db._query("FOR my IN mycollection RETURN my._key").toArray();
@startDocuBlockInline 01_workWithAQL_all
@EXAMPLE_ARANGOSH_OUTPUT{01_workWithAQL_all}
~addIgnoreCollection("mycollection")
db._create("mycollection")
db.mycollection.save({ _key: "testKey", Hello : "World" })
db._query('FOR my IN mycollection RETURN my._key').toArray()
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 01_workWithAQL_all
To pass bind parameters into a query, they can be specified as second argument to the
*_query* method:
arangosh> db._query("FOR c IN @@collection FILTER c._key == @key RETURN c._key", {
"@collection": "mycollection",
"key": "test1"
@startDocuBlockInline 02_workWithAQL_bindValues
@EXAMPLE_ARANGOSH_OUTPUT{02_workWithAQL_bindValues}
| db._query('FOR c IN @@collection FILTER c._key == @key RETURN c._key', {
| '@collection': 'mycollection',
| 'key': 'testKey'
}).toArray();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 02_workWithAQL_bindValues
Data-modifying AQL queries do not return a result, so the *toArray* method will always
return an empty array. To retrieve statistics for a data-modification query, use the
*getExtra* method:
arangosh> db._query("FOR i IN 1..100 INSERT { _key: CONCAT('test', TO_STRING(i)) } INTO mycollection").getExtra();
{
"stats" : {
"writesExecuted" : 100,
"writesIgnored" : 0,
"scannedFull" : 0,
"scannedIndex" : 0,
"filtered" : 0
},
"warnings" : [ ]
}
@startDocuBlockInline 03_workWithAQL_getExtra
@EXAMPLE_ARANGOSH_OUTPUT{03_workWithAQL_getExtra}
db._query("FOR i IN 1..100 INSERT { _key: CONCAT('test', TO_STRING(i)) } INTO mycollection").getExtra();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 03_workWithAQL_getExtra
The meaning of the statistics values is described below.
@ -43,28 +48,44 @@ executing it and iterating over the resulting cursor. If more control over the
result set iteration is needed, it is recommended to first create an
ArangoStatement object as follows:
arangosh> stmt = db._createStatement( { "query": "FOR i IN [ 1, 2 ] RETURN i * 2" } );
[object ArangoQueryCursor]
@startDocuBlockInline 04_workWithAQL_statements1
@EXAMPLE_ARANGOSH_OUTPUT{04_workWithAQL_statements1}
stmt = db._createStatement( { "query": "FOR i IN [ 1, 2 ] RETURN i * 2" } );
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 04_workWithAQL_statements1
To execute the query, use the *execute* method of the statement:
arangosh> c = stmt.execute();
[object ArangoQueryCursor]
@startDocuBlockInline 05_workWithAQL_statements2
@EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements2}
~var stmt = db._createStatement( { "query": "FOR i IN [ 1, 2 ] RETURN i * 2" } );
c = stmt.execute();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 05_workWithAQL_statements2
This has executed the query. The query results are available in a cursor
now. The cursor can return all its results at once using the *toArray* method.
This is a short-cut that you can use if you want to access the full result
set without iterating over it yourself.
arangosh> c.toArray();
[2, 4]
@startDocuBlockInline 05_workWithAQL_statements3
@EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements3}
~var stmt = db._createStatement( { "query": "FOR i IN [ 1, 2 ] RETURN i * 2" } );
~var c = stmt.execute();
c.toArray();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 05_workWithAQL_statements3
Cursors can also be used to iterate over the result set document-by-document.
To do so, use the *hasNext* and *next* methods of the cursor:
arangosh> while (c.hasNext()) { require("internal").print(c.next()); }
2
4
@startDocuBlockInline 05_workWithAQL_statements4
@EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements4}
~var stmt = db._createStatement( { "query": "FOR i IN [ 1, 2 ] RETURN i * 2" } );
~var c = stmt.execute();
while (c.hasNext()) { require("internal").print(c.next()); }
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 05_workWithAQL_statements4
Please note that you can iterate over the results of a cursor only once, and that
the cursor will be empty when you have fully iterated over it. To iterate over
@ -76,48 +97,74 @@ backwards iteration or random access to elements in a cursor.
To execute an AQL query using bind parameters, you need to create a statement first
and then bind the parameters to it before execution:
arangosh> stmt = db._createStatement( { "query": "FOR i IN [ @one, @two ] RETURN i * 2" } );
[object ArangoStatement]
arangosh> stmt.bind("one", 1);
arangosh> stmt.bind("two", 2);
arangosh> c = stmt.execute();
[object ArangoQueryCursor]
@startDocuBlockInline 05_workWithAQL_statements5
@EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements5}
var stmt = db._createStatement( { "query": "FOR i IN [ @one, @two ] RETURN i * 2" } );
stmt.bind("one", 1);
stmt.bind("two", 2);
c = stmt.execute();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 05_workWithAQL_statements5
The cursor results can then be dumped or iterated over as usual, e.g.:
arangosh> c.toArray();
[2, 4]
@startDocuBlockInline 05_workWithAQL_statements6
@EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements6}
~var stmt = db._createStatement( { "query": "FOR i IN [ @one, @two ] RETURN i * 2" } );
~stmt.bind("one", 1);
~stmt.bind("two", 2);
~var c = stmt.execute();
c.toArray();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 05_workWithAQL_statements6
or
arangosh> while (c.hasNext()) { require("internal").print(c.next()); }
2
4
@startDocuBlockInline 05_workWithAQL_statements7
@EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements7}
~var stmt = db._createStatement( { "query": "FOR i IN [ @one, @two ] RETURN i * 2" } );
~stmt.bind("one", 1);
~stmt.bind("two", 2);
~var c = stmt.execute();
while (c.hasNext()) { require("internal").print(c.next()); }
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 05_workWithAQL_statements7
Please note that bind parameters can also be passed into the *_createStatement* method directly,
making it a bit more convenient:
arangosh> stmt = db._createStatement( {
"query": "FOR i IN [ @one, @two ] RETURN i * 2",
"bindVars": {
"one": 1,
"two": 2
}
@startDocuBlockInline 05_workWithAQL_statements8
@EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements8}
|stmt = db._createStatement( {
| "query": "FOR i IN [ @one, @two ] RETURN i * 2",
| "bindVars": {
| "one": 1,
| "two": 2
| }
} );
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 05_workWithAQL_statements8
Cursors also optionally provide the total number of results. By default, they do not.
To make the server return the total number of results, you may set the *count* attribute to
*true* when creating a statement:
arangosh> stmt = db._createStatement( { "query": "FOR i IN [ 1, 2, 3, 4 ] RETURN i", "count": true } );
@startDocuBlockInline 05_workWithAQL_statements9
@EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements9}
stmt = db._createStatement( { "query": "FOR i IN [ 1, 2, 3, 4 ] RETURN i", "count": true } );
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 05_workWithAQL_statements9
After executing this query, you can use the *count* method of the cursor to get the
number of total results from the result set:
arangosh> c = stmt.execute();
[object ArangoQueryCursor]
arangosh> c.count();
4
@startDocuBlockInline 05_workWithAQL_statements10
@EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements10}
~var stmt = db._createStatement( { "query": "FOR i IN [ 1, 2, 3, 4 ] RETURN i", "count": true } );
var c = stmt.execute();
c.count();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 05_workWithAQL_statements10
Please note that the *count* method returns nothing if you did not specify the *count*
attribute when creating the query.
@ -143,17 +190,11 @@ A query that has been executed will always return execution statistics. Executio
can be retrieved by calling `getExtra()` on the cursor. The statistics are returned in the
return value's `stats` attribute:
arangosh> db._query("FOR i IN 1..100 INSERT { _key: CONCAT('test', TO_STRING(i)) } INTO mycollection").getExtra();
{
"stats" : {
"writesExecuted" : 100,
"writesIgnored" : 0,
"scannedFull" : 0,
"scannedIndex" : 0,
"filtered" : 0
},
"warnings" : [ ]
}
@startDocuBlockInline 06_workWithAQL_statementsExtra
@EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statementsExtra}
db._query("FOR i IN 1..100 INSERT { _key: CONCAT('anothertest', TO_STRING(i)) } INTO mycollection").getExtra();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 06_workWithAQL_statementsExtra
The meaning of the statistics attributes is as follows:
@ -211,92 +252,33 @@ Each plan in the result is an object with the following attributes:
Here is an example for retrieving the execution plan of a simple query:
```
arangosh> var stmt = db._createStatement("FOR user IN _users RETURN user");
arangosh> stmt.explain();
{
"plan" : {
"nodes" : [
{
"type" : "SingletonNode",
"dependencies" : [ ],
"id" : 1,
"estimatedCost" : 1
},
{
"type" : "EnumerateCollectionNode",
"dependencies" : [
1
],
"id" : 2,
"estimatedCost" : 1,
"database" : "_system",
"collection" : "_users",
"outVariable" : {
"id" : 0,
"name" : "user"
}
},
{
"type" : "ReturnNode",
"dependencies" : [
2
],
"id" : 3,
"estimatedCost" : 1,
"inVariable" : {
"id" : 0,
"name" : "user"
}
}
],
"rules" : [ ],
"collections" : [
{
"name" : "_users",
"type" : "read"
}
],
"variables" : [
{
"id" : 0,
"name" : "user"
}
],
"estimatedCost" : 1
},
"warnings" : [ ]
}
```
@startDocuBlockInline 07_workWithAQL_statementsExplain
@EXAMPLE_ARANGOSH_OUTPUT{07_workWithAQL_statementsExplain}
var stmt = db._createStatement("FOR user IN _users RETURN user");
stmt.explain();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 07_workWithAQL_statementsExplain
As the output of `explain` is very detailed, it is recommended to use some
scripting to make the output less verbose:
```
arangosh> formatPlan = function (plan) { return { estimatedCost: plan.estimatedCost, nodes: plan.nodes.map(function(node) { return node.type; }) }; };
arangosh> var stmt = db._createStatement("FOR user IN _users RETURN user");
arangosh> formatPlan(stmt.explain().plan);
{
"cost" : 1,
"nodes" : [
"SingletonNode",
"EnumerateCollectionNode",
"ReturnNode"
]
}
```
@startDocuBlockInline 08_workWithAQL_statementsPlans
@EXAMPLE_ARANGOSH_OUTPUT{08_workWithAQL_statementsPlans}
var formatPlan = function (plan) { return { estimatedCost: plan.estimatedCost, nodes: plan.nodes.map(function(node) { return node.type; }) }; };
formatPlan(stmt.explain().plan);
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 08_workWithAQL_statementsPlans
If a query contains bind parameters, they must be added to the statement **before**
`explain` is called:
```
arangosh> var stmt = db._createStatement("FOR doc IN @@collection FILTER doc.user == @user RETURN doc");
arangosh> stmt.bind({ "@collection" : "_users", "user" : "root" });
arangosh> stmt.explain();
{
...
}
```
@startDocuBlockInline 09_workWithAQL_statementsPlansBind
@EXAMPLE_ARANGOSH_OUTPUT{09_workWithAQL_statementsPlansBind}
var stmt = db._createStatement("FOR doc IN @@collection FILTER doc.user == @user RETURN doc");
stmt.bind({ "@collection" : "_users", "user" : "root" });
stmt.explain();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 09_workWithAQL_statementsPlansBind
In some cases the AQL optimizer creates multiple plans for a single query. By default
only the plan with the lowest total estimated cost is kept, and the other plans are
@ -305,39 +287,21 @@ with the option `allPlans` set to `true`.
In the following example, the optimizer has created two plans:
```
arangosh> var stmt = db._createStatement("FOR user IN _users FILTER user.user == 'root' RETURN user");
arangosh> stmt.explain({ allPlans: true }).plans.length;
2
```
@startDocuBlockInline 10_workWithAQL_statementsPlansOptimizer0
@EXAMPLE_ARANGOSH_OUTPUT{10_workWithAQL_statementsPlansOptimizer0}
var stmt = db._createStatement("FOR user IN _users FILTER user.user == 'root' RETURN user");
stmt.explain({ allPlans: true }).plans.length;
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 10_workWithAQL_statementsPlansOptimizer0
To see a slightly more compact version of the plan, the following transformation can be applied:
```
arangosh> stmt.explain({ allPlans: true }).plans.map(function(plan) { return formatPlan(plan); });
[
{
"cost" : 0.21,
"nodes" : [
"SingletonNode",
"IndexRangeNode",
"CalculationNode",
"FilterNode",
"ReturnNode"
]
},
{
"cost" : 0.21,
"nodes" : [
"SingletonNode",
"EnumerateCollectionNode",
"CalculationNode",
"FilterNode",
"ReturnNode"
]
}
]
```
@startDocuBlockInline 10_workWithAQL_statementsPlansOptimizer1
@EXAMPLE_ARANGOSH_OUTPUT{10_workWithAQL_statementsPlansOptimizer1}
~var stmt = db._createStatement("FOR user IN _users FILTER user.user == 'root' RETURN user");
stmt.explain({ allPlans: true }).plans.map(function(plan) { return formatPlan(plan); });
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 10_workWithAQL_statementsPlansOptimizer1
`explain` will also accept the following additional options:
- *maxPlans*: limits the maximum number of plans that are created by the AQL query optimizer
@ -348,18 +312,23 @@ arangosh> stmt.explain({ allPlans: true }).plans.map(function(plan) { return for
The following example disables all optimizer rules but `remove-redundant-calculations`:
```
arangosh> stmt.explain({ optimizer: { rules: [ "-all", "+remove-redundant-calculations" ] } });
```
@startDocuBlockInline 10_workWithAQL_statementsPlansOptimizer2
@EXAMPLE_ARANGOSH_OUTPUT{10_workWithAQL_statementsPlansOptimizer2}
~var stmt = db._createStatement("FOR user IN _users FILTER user.user == 'root' RETURN user");
stmt.explain({ optimizer: { rules: [ "-all", "+remove-redundant-calculations" ] } });
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 10_workWithAQL_statementsPlansOptimizer2
The contents of an execution plan are meant to be machine-readable. To get a human-readable
version of a query's execution plan, the following commnands can be used:
```js
arangosh> var query = "FOR doc IN collection FILTER doc.value > 42 RETURN doc";
arangosh> require("org/arangodb/aql/explainer").explain(query);
```
@startDocuBlockInline 10_workWithAQL_statementsPlansOptimizer3
@EXAMPLE_ARANGOSH_OUTPUT{10_workWithAQL_statementsPlansOptimizer3}
var query = "FOR doc IN mycollection FILTER doc.value > 42 RETURN doc";
require("org/arangodb/aql/explainer").explain(query, {colors:false});
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 10_workWithAQL_statementsPlansOptimizer3
The above command prints the query's execution plan in the ArangoShell directly, focusing
on the most important information.
@ -380,17 +349,11 @@ Addtionally, the internal representation of the query, the query's abstract synt
be returned in the `ast` attribute of the result. Please note that the abstract syntax tree
will be returned without any optimizations applied to it.
```
arangosh> var stmt = db._createStatement("FOR doc IN @@collection FILTER doc.foo == @bar RETURN doc");
arangosh> stmt.parse();
{
"bindVars" : [
"bar",
"@collection"
],
"collections" : [ ],
"ast" : [
...
]
}
```
@startDocuBlockInline 11_workWithAQL_parseQueries
@EXAMPLE_ARANGOSH_OUTPUT{11_workWithAQL_parseQueries}
var stmt = db._createStatement("FOR doc IN @@collection FILTER doc.foo == @bar RETURN doc");
stmt.parse();
~addIgnoreCollection("mycollection")
~db._drop("mycollection")
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 11_workWithAQL_parseQueries

View File

@ -28,12 +28,12 @@ embedded version in the browser. Using the command-line tool has the
advantage that you can use autocompletion.
unix> arangosh --server.password ""
_
__ _ _ __ __ _ _ __ __ _ ___ ___| |__
_
__ _ _ __ __ _ _ __ __ _ ___ ___| |__
/ _` | '__/ _` | '_ \ / _` |/ _ \/ __| '_ \
| (_| | | | (_| | | | | (_| | (_) \__ \ | | |
\__,_|_| \__,_|_| |_|\__, |\___/|___/_| |_|
|___/
|___/
Welcome to arangosh 2.x.y. Copyright (c) 2012 triAGENS GmbH.
Using Google V8 4.1.0.27 JavaScript engine.