mirror of https://gitee.com/bigwinds/arangodb
Implement dynamic examples for invoking AQL tutorial
This commit is contained in:
parent
500371d658
commit
b9a25e02c0
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue