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 selected database and return the query results in a cursor. The results of the cursor
can be printed using its *toArray* method: 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 To pass bind parameters into a query, they can be specified as second argument to the
*_query* method: *_query* method:
arangosh> db._query("FOR c IN @@collection FILTER c._key == @key RETURN c._key", { @startDocuBlockInline 02_workWithAQL_bindValues
"@collection": "mycollection", @EXAMPLE_ARANGOSH_OUTPUT{02_workWithAQL_bindValues}
"key": "test1" | db._query('FOR c IN @@collection FILTER c._key == @key RETURN c._key', {
| '@collection': 'mycollection',
| 'key': 'testKey'
}).toArray(); }).toArray();
@END_EXAMPLE_ARANGOSH_OUTPUT
@endDocuBlock 02_workWithAQL_bindValues
Data-modifying AQL queries do not return a result, so the *toArray* method will always 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 return an empty array. To retrieve statistics for a data-modification query, use the
*getExtra* method: *getExtra* method:
arangosh> db._query("FOR i IN 1..100 INSERT { _key: CONCAT('test', TO_STRING(i)) } INTO mycollection").getExtra(); @startDocuBlockInline 03_workWithAQL_getExtra
{ @EXAMPLE_ARANGOSH_OUTPUT{03_workWithAQL_getExtra}
"stats" : { db._query("FOR i IN 1..100 INSERT { _key: CONCAT('test', TO_STRING(i)) } INTO mycollection").getExtra();
"writesExecuted" : 100, @END_EXAMPLE_ARANGOSH_OUTPUT
"writesIgnored" : 0, @endDocuBlock 03_workWithAQL_getExtra
"scannedFull" : 0,
"scannedIndex" : 0,
"filtered" : 0
},
"warnings" : [ ]
}
The meaning of the statistics values is described below. 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 result set iteration is needed, it is recommended to first create an
ArangoStatement object as follows: ArangoStatement object as follows:
arangosh> stmt = db._createStatement( { "query": "FOR i IN [ 1, 2 ] RETURN i * 2" } ); @startDocuBlockInline 04_workWithAQL_statements1
[object ArangoQueryCursor] @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: To execute the query, use the *execute* method of the statement:
arangosh> c = stmt.execute(); @startDocuBlockInline 05_workWithAQL_statements2
[object ArangoQueryCursor] @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 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. 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 This is a short-cut that you can use if you want to access the full result
set without iterating over it yourself. set without iterating over it yourself.
arangosh> c.toArray(); @startDocuBlockInline 05_workWithAQL_statements3
[2, 4] @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. 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: To do so, use the *hasNext* and *next* methods of the cursor:
arangosh> while (c.hasNext()) { require("internal").print(c.next()); } @startDocuBlockInline 05_workWithAQL_statements4
2 @EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements4}
4 ~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 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 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 To execute an AQL query using bind parameters, you need to create a statement first
and then bind the parameters to it before execution: and then bind the parameters to it before execution:
arangosh> stmt = db._createStatement( { "query": "FOR i IN [ @one, @two ] RETURN i * 2" } ); @startDocuBlockInline 05_workWithAQL_statements5
[object ArangoStatement] @EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements5}
arangosh> stmt.bind("one", 1); var stmt = db._createStatement( { "query": "FOR i IN [ @one, @two ] RETURN i * 2" } );
arangosh> stmt.bind("two", 2); stmt.bind("one", 1);
arangosh> c = stmt.execute(); stmt.bind("two", 2);
[object ArangoQueryCursor] 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.: The cursor results can then be dumped or iterated over as usual, e.g.:
arangosh> c.toArray(); @startDocuBlockInline 05_workWithAQL_statements6
[2, 4] @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 or
arangosh> while (c.hasNext()) { require("internal").print(c.next()); } @startDocuBlockInline 05_workWithAQL_statements7
2 @EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements7}
4 ~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, Please note that bind parameters can also be passed into the *_createStatement* method directly,
making it a bit more convenient: making it a bit more convenient:
arangosh> stmt = db._createStatement( { @startDocuBlockInline 05_workWithAQL_statements8
"query": "FOR i IN [ @one, @two ] RETURN i * 2", @EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements8}
"bindVars": { |stmt = db._createStatement( {
"one": 1, | "query": "FOR i IN [ @one, @two ] RETURN i * 2",
"two": 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. 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 To make the server return the total number of results, you may set the *count* attribute to
*true* when creating a statement: *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 After executing this query, you can use the *count* method of the cursor to get the
number of total results from the result set: number of total results from the result set:
arangosh> c = stmt.execute(); @startDocuBlockInline 05_workWithAQL_statements10
[object ArangoQueryCursor] @EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statements10}
arangosh> c.count(); ~var stmt = db._createStatement( { "query": "FOR i IN [ 1, 2, 3, 4 ] RETURN i", "count": true } );
4 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* Please note that the *count* method returns nothing if you did not specify the *count*
attribute when creating the query. 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 can be retrieved by calling `getExtra()` on the cursor. The statistics are returned in the
return value's `stats` attribute: return value's `stats` attribute:
arangosh> db._query("FOR i IN 1..100 INSERT { _key: CONCAT('test', TO_STRING(i)) } INTO mycollection").getExtra(); @startDocuBlockInline 06_workWithAQL_statementsExtra
{ @EXAMPLE_ARANGOSH_OUTPUT{05_workWithAQL_statementsExtra}
"stats" : { db._query("FOR i IN 1..100 INSERT { _key: CONCAT('anothertest', TO_STRING(i)) } INTO mycollection").getExtra();
"writesExecuted" : 100, @END_EXAMPLE_ARANGOSH_OUTPUT
"writesIgnored" : 0, @endDocuBlock 06_workWithAQL_statementsExtra
"scannedFull" : 0,
"scannedIndex" : 0,
"filtered" : 0
},
"warnings" : [ ]
}
The meaning of the statistics attributes is as follows: 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: Here is an example for retrieving the execution plan of a simple query:
``` @startDocuBlockInline 07_workWithAQL_statementsExplain
arangosh> var stmt = db._createStatement("FOR user IN _users RETURN user"); @EXAMPLE_ARANGOSH_OUTPUT{07_workWithAQL_statementsExplain}
arangosh> stmt.explain(); var stmt = db._createStatement("FOR user IN _users RETURN user");
{ stmt.explain();
"plan" : { @END_EXAMPLE_ARANGOSH_OUTPUT
"nodes" : [ @endDocuBlock 07_workWithAQL_statementsExplain
{
"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" : [ ]
}
```
As the output of `explain` is very detailed, it is recommended to use some As the output of `explain` is very detailed, it is recommended to use some
scripting to make the output less verbose: scripting to make the output less verbose:
``` @startDocuBlockInline 08_workWithAQL_statementsPlans
arangosh> formatPlan = function (plan) { return { estimatedCost: plan.estimatedCost, nodes: plan.nodes.map(function(node) { return node.type; }) }; }; @EXAMPLE_ARANGOSH_OUTPUT{08_workWithAQL_statementsPlans}
arangosh> var stmt = db._createStatement("FOR user IN _users RETURN user"); var formatPlan = function (plan) { return { estimatedCost: plan.estimatedCost, nodes: plan.nodes.map(function(node) { return node.type; }) }; };
arangosh> formatPlan(stmt.explain().plan); formatPlan(stmt.explain().plan);
{ @END_EXAMPLE_ARANGOSH_OUTPUT
"cost" : 1, @endDocuBlock 08_workWithAQL_statementsPlans
"nodes" : [
"SingletonNode",
"EnumerateCollectionNode",
"ReturnNode"
]
}
```
If a query contains bind parameters, they must be added to the statement **before** If a query contains bind parameters, they must be added to the statement **before**
`explain` is called: `explain` is called:
``` @startDocuBlockInline 09_workWithAQL_statementsPlansBind
arangosh> var stmt = db._createStatement("FOR doc IN @@collection FILTER doc.user == @user RETURN doc"); @EXAMPLE_ARANGOSH_OUTPUT{09_workWithAQL_statementsPlansBind}
arangosh> stmt.bind({ "@collection" : "_users", "user" : "root" }); var stmt = db._createStatement("FOR doc IN @@collection FILTER doc.user == @user RETURN doc");
arangosh> stmt.explain(); 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 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 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: In the following example, the optimizer has created two plans:
``` @startDocuBlockInline 10_workWithAQL_statementsPlansOptimizer0
arangosh> var stmt = db._createStatement("FOR user IN _users FILTER user.user == 'root' RETURN user"); @EXAMPLE_ARANGOSH_OUTPUT{10_workWithAQL_statementsPlansOptimizer0}
arangosh> stmt.explain({ allPlans: true }).plans.length; var stmt = db._createStatement("FOR user IN _users FILTER user.user == 'root' RETURN user");
2 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: To see a slightly more compact version of the plan, the following transformation can be applied:
``` @startDocuBlockInline 10_workWithAQL_statementsPlansOptimizer1
arangosh> stmt.explain({ allPlans: true }).plans.map(function(plan) { return formatPlan(plan); }); @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); });
"cost" : 0.21, @END_EXAMPLE_ARANGOSH_OUTPUT
"nodes" : [ @endDocuBlock 10_workWithAQL_statementsPlansOptimizer1
"SingletonNode",
"IndexRangeNode",
"CalculationNode",
"FilterNode",
"ReturnNode"
]
},
{
"cost" : 0.21,
"nodes" : [
"SingletonNode",
"EnumerateCollectionNode",
"CalculationNode",
"FilterNode",
"ReturnNode"
]
}
]
```
`explain` will also accept the following additional options: `explain` will also accept the following additional options:
- *maxPlans*: limits the maximum number of plans that are created by the AQL query optimizer - *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`: The following example disables all optimizer rules but `remove-redundant-calculations`:
``` @startDocuBlockInline 10_workWithAQL_statementsPlansOptimizer2
arangosh> stmt.explain({ optimizer: { rules: [ "-all", "+remove-redundant-calculations" ] } }); @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 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: version of a query's execution plan, the following commnands can be used:
```js @startDocuBlockInline 10_workWithAQL_statementsPlansOptimizer3
arangosh> var query = "FOR doc IN collection FILTER doc.value > 42 RETURN doc"; @EXAMPLE_ARANGOSH_OUTPUT{10_workWithAQL_statementsPlansOptimizer3}
arangosh> require("org/arangodb/aql/explainer").explain(query); 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 The above command prints the query's execution plan in the ArangoShell directly, focusing
on the most important information. 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 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. will be returned without any optimizations applied to it.
``` @startDocuBlockInline 11_workWithAQL_parseQueries
arangosh> var stmt = db._createStatement("FOR doc IN @@collection FILTER doc.foo == @bar RETURN doc"); @EXAMPLE_ARANGOSH_OUTPUT{11_workWithAQL_parseQueries}
arangosh> stmt.parse(); var stmt = db._createStatement("FOR doc IN @@collection FILTER doc.foo == @bar RETURN doc");
{ stmt.parse();
"bindVars" : [ ~addIgnoreCollection("mycollection")
"bar", ~db._drop("mycollection")
"@collection" @END_EXAMPLE_ARANGOSH_OUTPUT
], @endDocuBlock 11_workWithAQL_parseQueries
"collections" : [ ],
"ast" : [
...
]
}
```