mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of github.com:triAGENS/ArangoDB into devel
This commit is contained in:
commit
17f68a94ff
|
@ -19,7 +19,7 @@ Let's start with an example that modifies existing documents in a collection
|
|||
FILTER u.status == 'not active'
|
||||
UPDATE u WITH { status: 'inactive' } IN users
|
||||
|
||||
Note there is no need to combine a data-modification query with other
|
||||
Note that there is no need to combine a data-modification query with other
|
||||
AQL operations such as *FOR* and *FILTER*. For example, the following
|
||||
stripped-down *update* query will work, too. It will *update* one document
|
||||
(with key *foo*) in collection *users*:
|
||||
|
@ -34,13 +34,42 @@ Now, let's copy the contents of the collection *users* into the collection
|
|||
|
||||
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 establish via the documents' keys:
|
||||
collections is established via the documents' keys:
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.status == 'deleted'
|
||||
REMOVE u IN backup
|
||||
|
||||
|
||||
!SUBSECTION Returning documents
|
||||
|
||||
To return documents from a data-modification query, the `INSERT`, `REMOVE`,
|
||||
`UPDATE` or `REPLACE` statement must be immediately followed by a `LET`
|
||||
statement that assigns either the pseudo-value `NEW` or `OLD` to a user-defined
|
||||
variable. The `LET` statement must be followed by a `RETURN` statement that
|
||||
returns the variable introduced by `LET`:
|
||||
|
||||
FOR i IN 1..100
|
||||
INSERT { value: i } IN test LET inserted = NEW RETURN inserted
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.status == 'deleted'
|
||||
REMOVE u IN users LET removed = OLD RETURN removed
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.status == 'not active'
|
||||
UPDATE u WITH { status: 'inactive' } IN users LET updated = NEW RETURN updated
|
||||
|
||||
`NEW` refers to the inserted or modified document revision, and `OLD` refers
|
||||
to the document revision before update or removal. `INSERT` statements can
|
||||
only refer to the `NEW` pseudo-value, and `REMOVE` operations only to `OLD`.
|
||||
`UPDATE` and `REPLACE` can refer to either.
|
||||
|
||||
In all cases the full documents will be returned with all their attributes,
|
||||
including the potentially auto-generated attributes such as `_id`, `_key`, or `_rev`
|
||||
and the attributes not specified in the update expression of a partial update.
|
||||
|
||||
|
||||
!SUBSECTION Restrictions
|
||||
|
||||
The name of the modified collection (*users* and *backup* in the above cases)
|
||||
|
|
|
@ -186,7 +186,11 @@ repeated computations of the same value at multiple parts of a query.
|
|||
```
|
||||
FOR u IN users
|
||||
LET numRecommendations = LENGTH(u.recommendations)
|
||||
RETURN { "user" : u, "numRecommendations" : numRecommendations, "isPowerUser" : numRecommendations >= 10 }
|
||||
RETURN {
|
||||
"user" : u,
|
||||
"numRecommendations" : numRecommendations,
|
||||
"isPowerUser" : numRecommendations >= 10
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, the computation of the number of recommendations is
|
||||
|
@ -446,20 +450,22 @@ do not need to be identical to the ones produced by a preceding *FOR* statement:
|
|||
|
||||
```
|
||||
FOR i IN 1..1000
|
||||
REMOVE { _key: CONCAT('test', TO_STRING(i)) } IN users
|
||||
REMOVE { _key: CONCAT('test', i) } IN users
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.active == false
|
||||
REMOVE { _key: u._key } IN backup
|
||||
```
|
||||
|
||||
!SUBSUBSECTION Setting query options
|
||||
|
||||
*options* can be used to suppress query errors that may occur when trying to
|
||||
remove non-existing documents. For example, the following query will fail if one
|
||||
of the to-be-deleted documents does not exist:
|
||||
|
||||
```
|
||||
FOR i IN 1..1000
|
||||
REMOVE { _key: CONCAT('test', TO_STRING(i)) } IN users
|
||||
REMOVE { _key: CONCAT('test', i) } IN users
|
||||
```
|
||||
|
||||
By specifying the *ignoreErrors* query option, these errors can be suppressed so
|
||||
|
@ -467,7 +473,7 @@ the query completes:
|
|||
|
||||
```
|
||||
FOR i IN 1..1000
|
||||
REMOVE { _key: CONCAT('test', TO_STRING(i)) } IN users OPTIONS { ignoreErrors: true }
|
||||
REMOVE { _key: CONCAT('test', i) } IN users OPTIONS { ignoreErrors: true }
|
||||
```
|
||||
|
||||
To make sure data has been written to disk when a query returns, there is the *waitForSync*
|
||||
|
@ -475,7 +481,26 @@ query option:
|
|||
|
||||
```
|
||||
FOR i IN 1..1000
|
||||
REMOVE { _key: CONCAT('test', TO_STRING(i)) } IN users OPTIONS { waitForSync: true }
|
||||
REMOVE { _key: CONCAT('test', i) } IN users OPTIONS { waitForSync: true }
|
||||
```
|
||||
|
||||
!SUBSUBSECTION Returning the removed documents
|
||||
|
||||
The removed documents can also be returned by the query. In this case, the `REMOVE`
|
||||
statement must be directly followed by a special `LET` statement and a `RETURN`
|
||||
statement. The `LET` statement is limited to assigning the pseudo-value `OLD`
|
||||
to a variable, and the `RETURN` statement is limited to returning this variable:
|
||||
|
||||
```
|
||||
REMOVE key-expression IN collection options LET variable-name = OLD RETURN variable-name
|
||||
```
|
||||
|
||||
Following is an example using a variable named `removed` to return the removed
|
||||
documents:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
REMOVE u IN users LET removed = OLD RETURN removed
|
||||
```
|
||||
|
||||
!SUBSECTION UPDATE
|
||||
|
@ -535,19 +560,21 @@ to the ones produced by a preceding *FOR* statement:
|
|||
|
||||
```
|
||||
FOR i IN 1..1000
|
||||
UPDATE CONCAT('test', TO_STRING(i)) WITH { foobar: true } IN users
|
||||
UPDATE CONCAT('test', i) WITH { foobar: true } IN users
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.active == false
|
||||
UPDATE u WITH { status: 'inactive' } IN backup
|
||||
```
|
||||
|
||||
!SUBSUBSECTION Setting query options
|
||||
|
||||
*options* can be used to suppress query errors that may occur when trying to
|
||||
update non-existing documents or violating unique key constraints:
|
||||
|
||||
```
|
||||
FOR i IN 1..1000
|
||||
UPDATE { _key: CONCAT('test', TO_STRING(i)) } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
|
||||
UPDATE { _key: CONCAT('test', i) } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
|
||||
```
|
||||
|
||||
An update operation will only update the attributes specified in *document* and
|
||||
|
@ -603,6 +630,42 @@ FOR u IN users
|
|||
UPDATE u WITH { foobar: true } IN users OPTIONS { waitForSync: true }
|
||||
```
|
||||
|
||||
!SUBSUBSECTION Returning the modified documents
|
||||
|
||||
The modified documents can also be returned by the query. In this case, the `UPDATE`
|
||||
statement must be directly followed by a special `LET` statement and a `RETURN`
|
||||
statement. The `LET` statement is limited to assigning either the pseudo-value `OLD`
|
||||
or `NEW` to a variable, and the `RETURN` statement is limited to returning this variable.
|
||||
The `OLD` pseudo-value refers to the document revisions before the update, and `NEW`
|
||||
refers to document revisions after the update.
|
||||
|
||||
```
|
||||
UPDATE document IN collection options LET variable-name = OLD RETURN variable-name
|
||||
UPDATE document IN collection options LET variable-name = NEW RETURN variable-name
|
||||
UPDATE key-expression WITH document IN collection options LET variable-name = OLD RETURN variable-name
|
||||
UPDATE key-expression WITH document IN collection options LET variable-name = NEW RETURN variable-name
|
||||
```
|
||||
|
||||
Following is an example using a variable named `previous` to return the original
|
||||
documents before modification:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
UPDATE u WITH { value: "test" } LET previous = OLD RETURN previous
|
||||
```
|
||||
|
||||
The following query uses the `NEW` pseudo-value to return the updated
|
||||
documents:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
UPDATE u WITH { value: "test" } LET updated = NEW RETURN updated
|
||||
```
|
||||
|
||||
In both cases, the returned documents will contain all attributes, even
|
||||
those not specified in the update expression.
|
||||
|
||||
|
||||
!SUBSECTION REPLACE
|
||||
|
||||
The *REPLACE* keyword can be used to completely replace documents in a collection. On a
|
||||
|
@ -666,19 +729,21 @@ to the ones produced by a preceding *FOR* statement:
|
|||
|
||||
```
|
||||
FOR i IN 1..1000
|
||||
REPLACE CONCAT('test', TO_STRING(i)) WITH { foobar: true } IN users
|
||||
REPLACE CONCAT('test', i) WITH { foobar: true } IN users
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.active == false
|
||||
REPLACE u WITH { status: 'inactive', name: u.name } IN backup
|
||||
```
|
||||
|
||||
!SUBSUBSECTION Setting query options
|
||||
|
||||
*options* can be used to suppress query errors that may occur when trying to
|
||||
replace non-existing documents or when violating unique key constraints:
|
||||
|
||||
```
|
||||
FOR i IN 1..1000
|
||||
REPLACE { _key: CONCAT('test', TO_STRING(i)) } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
|
||||
REPLACE { _key: CONCAT('test', i) } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
|
||||
```
|
||||
|
||||
To make sure data are durable when a replace query returns, there is the *waitForSync*
|
||||
|
@ -686,9 +751,45 @@ query option:
|
|||
|
||||
```
|
||||
FOR i IN 1..1000
|
||||
REPLACE { _key: CONCAT('test', TO_STRING(i)) } WITH { foobar: true } IN users OPTIONS { waitForSync: true }
|
||||
REPLACE { _key: CONCAT('test', i) } WITH { foobar: true } IN users OPTIONS { waitForSync: true }
|
||||
```
|
||||
|
||||
!SUBSUBSECTION Returning the modified documents
|
||||
|
||||
The modified documents can also be returned by the query. In this case, the `REPLACE`
|
||||
statement must be directly followed by a special `LET` statement and a `RETURN`
|
||||
statement. The `LET` statement is limited to assigning either the pseudo-value `OLD`
|
||||
or `NEW` to a variable, and the `RETURN` statement is limited to returning this variable.
|
||||
The `OLD` pseudo-value refers to the document revisions before the update, and `NEW`
|
||||
refers to document revisions after the update.
|
||||
|
||||
```
|
||||
REPLACE document IN collection options LET variable-name = OLD RETURN variable-name
|
||||
REPLACE document IN collection options LET variable-name = NEW RETURN variable-name
|
||||
REPLACE key-expression WITH document IN collection options LET variable-name = OLD RETURN variable-name
|
||||
REPLACE key-expression WITH document IN collection options LET variable-name = NEW RETURN variable-name
|
||||
```
|
||||
|
||||
Following is an example using a variable named `previous` to return the original
|
||||
documents before modification:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
REPLACE u WITH { value: "test" } LET previous = OLD RETURN previous
|
||||
```
|
||||
|
||||
The following query uses the `NEW` pseudo-value to return the replaced
|
||||
documents:
|
||||
|
||||
```
|
||||
FOR u IN users
|
||||
REPLACE u WITH { value: "test" } LET replaced = NEW RETURN replaced
|
||||
```
|
||||
|
||||
In both cases, the returned documents will contain all attributes, even
|
||||
those not specified in the replace expression.
|
||||
|
||||
|
||||
!SUBSECTION INSERT
|
||||
|
||||
The *INSERT* keyword can be used to insert new documents into a collection. On a
|
||||
|
@ -728,12 +829,14 @@ FOR u IN users
|
|||
INSERT { _from: u._id, _to: p._id } IN recommendations
|
||||
```
|
||||
|
||||
!SUBSUBSECTION Setting query options
|
||||
|
||||
*options* can be used to suppress query errors that may occur when violating unique
|
||||
key constraints:
|
||||
|
||||
```
|
||||
FOR i IN 1..1000
|
||||
INSERT { _key: CONCAT('test', TO_STRING(i)), name: "test" } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
|
||||
INSERT { _key: CONCAT('test', i), name: "test" } WITH { foobar: true } IN users OPTIONS { ignoreErrors: true }
|
||||
```
|
||||
|
||||
To make sure data are durable when an insert query returns, there is the *waitForSync*
|
||||
|
@ -741,5 +844,27 @@ query option:
|
|||
|
||||
```
|
||||
FOR i IN 1..1000
|
||||
INSERT { _key: CONCAT('test', TO_STRING(i)), name: "test" } WITH { foobar: true } IN users OPTIONS { waitForSync: true }
|
||||
INSERT { _key: CONCAT('test', i), name: "test" } WITH { foobar: true } IN users OPTIONS { waitForSync: true }
|
||||
```
|
||||
|
||||
!SUBSUBSECTION Returning the inserted documents
|
||||
|
||||
The inserted documents can also be returned by the query. In this case, the `INSERT`
|
||||
statement must be directly followed by a special `LET` statement and a `RETURN`
|
||||
statement. The `LET` statement is limited to assigning the pseudo-value `NEW`
|
||||
to a variable, and the `RETURN` statement is limited to returning this variable:
|
||||
|
||||
```
|
||||
INSERT document IN collection options LET variable-name = OLD RETURN variable-name
|
||||
```
|
||||
|
||||
Following is an example using a variable named `inserted` to return the inserted
|
||||
documents:
|
||||
|
||||
```
|
||||
FOR i IN 1..100
|
||||
INSERT { value: i } LET inserted = NEW RETURN inserted
|
||||
```
|
||||
|
||||
The returned documents will contain all attributes, even those auto-generated by
|
||||
the database (e.g. `_id`, `_key`, `_rev`, `_from`, and `_to`).
|
||||
|
|
|
@ -167,7 +167,7 @@ is available that describes how to compile ArangoDB from source on Ubuntu.
|
|||
Verify that your system contains
|
||||
|
||||
* the GNU C/C++ compilers "gcc" and "g++" and the standard C/C++ libraries, with support
|
||||
for C++11. You will need version gcc number 4.8.1 or higher. For "clang" and "clang++",
|
||||
for C++11. You will need version gcc 4.8.1 or higher. For "clang" and "clang++",
|
||||
you will need at least version 3.4.
|
||||
* the GNU autotools (autoconf, automake)
|
||||
* GNU make
|
||||
|
@ -278,8 +278,12 @@ the code.
|
|||
|
||||
This option activates additional code in the server that intentionally makes the
|
||||
server crash or misbehave (e.g. by pretending the system ran out of memory). This
|
||||
option is useful to test the recovery after a crash and also several edge cases.
|
||||
option is useful for writing tests.
|
||||
|
||||
`--enable-v8-debug`
|
||||
|
||||
Builds a debug version of the V8 library. This is useful only when working on the
|
||||
V8 integration inside ArangoDB.
|
||||
|
||||
!SUBSECTION Compiling Go
|
||||
|
||||
|
|
|
@ -99,6 +99,39 @@ statement and move the random iteration into the appropriate `EnumerateCollectio
|
|||
This is usually more efficient than individually enumerating and sorting.
|
||||
|
||||
|
||||
!SUBSECTION Data-modification queries returning documents
|
||||
|
||||
`INSERT`, `REMOVE`, `UPDATE` or `REPLACE` queries now can optionally return
|
||||
the documents inserted, removed, updated, or replaced. This is helpful for tracking
|
||||
the auto-generated attributes (e.g. `_key`, `_rev`) created by an `INSERT` and in
|
||||
a lot of other situations.
|
||||
|
||||
In order to return documents from a data-modification query, the statement must
|
||||
immediately be immediately followed by a `LET` statement that assigns either the
|
||||
pseudo-value `NEW` or `OLD` to a variable. This `LET` statement must be followed
|
||||
by a `RETURN` statement that returns the variable introduced by `LET`:
|
||||
|
||||
FOR i IN 1..100
|
||||
INSERT { value: i } IN test LET inserted = NEW RETURN inserted
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.status == 'deleted'
|
||||
REMOVE u IN users LET removed = OLD RETURN removed
|
||||
|
||||
FOR u IN users
|
||||
FILTER u.status == 'not active'
|
||||
UPDATE u WITH { status: 'inactive' } IN users LET updated = NEW RETURN updated
|
||||
|
||||
`NEW` refers to the inserted or modified document revision, and `OLD` refers
|
||||
to the document revision before update or removal. `INSERT` statements can
|
||||
only refer to the `NEW` pseudo-value, and `REMOVE` operations only to `OLD`.
|
||||
`UPDATE` and `REPLACE` can refer to either.
|
||||
|
||||
In all cases the full documents will be returned with all their attributes,
|
||||
including the potentially auto-generated attributes such as `_id`, `_key`, or `_rev`
|
||||
and the attributes not specified in the update expression of a partial update.
|
||||
|
||||
|
||||
!SUBSECTION Language improvements
|
||||
|
||||
!SUBSUBSECTION `COUNT` clause
|
||||
|
|
|
@ -109,7 +109,7 @@ bool Parser::configureWriteQuery (QueryType type,
|
|||
case AQL_QUERY_REMOVE:
|
||||
if (newOld != nullptr) {
|
||||
if (! TRI_CaseEqualString(newOld, "OLD")) {
|
||||
_query->registerError(TRI_ERROR_QUERY_PARSE, "OLD expected");
|
||||
_query->registerError(TRI_ERROR_QUERY_PARSE, "remove operations can only refer to 'OLD' value");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ bool Parser::configureWriteQuery (QueryType type,
|
|||
case AQL_QUERY_INSERT:
|
||||
if (newOld != nullptr) {
|
||||
if (! TRI_CaseEqualString(newOld, "NEW")) {
|
||||
_query->registerError(TRI_ERROR_QUERY_PARSE, "NEW expected");
|
||||
_query->registerError(TRI_ERROR_QUERY_PARSE, "insert operations can only refer to 'NEW' value");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ bool Parser::configureWriteQuery (QueryType type,
|
|||
case AQL_QUERY_REPLACE:
|
||||
if (newOld != nullptr) {
|
||||
if (! TRI_CaseEqualString(newOld, "OLD") && ! TRI_CaseEqualString(newOld, "NEW")) {
|
||||
_query->registerError(TRI_ERROR_QUERY_PARSE, "NEW or OLD expected");
|
||||
_query->registerError(TRI_ERROR_QUERY_PARSE, "update/replace operations can only refer to 'NEW' or 'OLD' values");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ bool Parser::configureWriteQuery (QueryType type,
|
|||
|
||||
if (varInto != nullptr && varReturn != nullptr) {
|
||||
if (! TRI_CaseEqualString(varInto, varReturn)) {
|
||||
_query->registerError(TRI_ERROR_QUERY_PARSE, "invalid variable used in data-modification operation");
|
||||
_query->registerError(TRI_ERROR_QUERY_PARSE, "invalid variable used in data-modification operation return value");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ var validateDeleteGone = function (collection, results) {
|
|||
assertEqual(collection.document(results[index]._key), {});
|
||||
fail();
|
||||
}
|
||||
catch(e) {
|
||||
catch (e) {
|
||||
assertTrue(e.errorNum !== undefined, "unexpected error format while calling checking for deleted entry");
|
||||
assertEqual(errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code, e.errorNum, "unexpected error code (" + e.errorMessage + "): ");
|
||||
}
|
||||
|
@ -264,6 +264,14 @@ function ahuacatlModifySuite () {
|
|||
assertQueryError(errors.ERROR_QUERY_PARSE.code, "UPDATE 'abc' WITH { } IN @@cn LET updated = NEW RETURN foo", { "@cn": cn1 });
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test variable names
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testInvalidVariableNames3 : function () {
|
||||
assertQueryError(errors.ERROR_QUERY_PARSE.code, "FOR i IN 1..1 UPDATE 'abc' WITH { } IN @@cn LET updated = NEW RETURN i", { "@cn": cn1 });
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test empty results
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue