mirror of https://gitee.com/bigwinds/arangodb
316 lines
9.5 KiB
Plaintext
316 lines
9.5 KiB
Plaintext
Data Queries
|
|
============
|
|
|
|
Data Access Queries
|
|
-------------------
|
|
|
|
Retrieving data from the database with AQL does always include a **RETURN**
|
|
operation. It can be used to return a static value, such as a string:
|
|
|
|
```js
|
|
RETURN "Hello ArangoDB!"
|
|
```
|
|
|
|
The query result is always an array of elements, even if a single element was
|
|
returned and contains a single element in that case: `["Hello ArangoDB!"]`
|
|
|
|
The function `DOCUMENT()` can be called to retrieve a single document via
|
|
its document handle, for instance:
|
|
|
|
```js
|
|
RETURN DOCUMENT("users/phil")
|
|
```
|
|
|
|
*RETURN* is usually accompanied by a **FOR** loop to iterate over the
|
|
documents of a collection. The following query executes the loop body for all
|
|
documents of a collection called *users*. Each document is returned unchanged
|
|
in this example:
|
|
|
|
```js
|
|
FOR doc IN users
|
|
RETURN doc
|
|
```
|
|
|
|
Instead of returning the raw `doc`, one can easily create a projection:
|
|
|
|
```js
|
|
FOR doc IN users
|
|
RETURN { user: doc, newAttribute: true }
|
|
```
|
|
|
|
For every user document, an object with two attributes is returned. The value
|
|
of the attribute *user* is set to the content of the user document, and
|
|
*newAttribute* is a static attribute with the boolean value *true*.
|
|
|
|
Operations like **FILTER**, **SORT** and **LIMIT** can be added to the loop body
|
|
to narrow and order the result. Instead of above shown call to `DOCUMENT()`,
|
|
one can also retrieve the document that describes user *phil* like so:
|
|
|
|
```js
|
|
FOR doc IN users
|
|
FILTER doc._key == "phil"
|
|
RETURN doc
|
|
```
|
|
|
|
The document key is used in this example, but any other attribute could equally
|
|
be used for filtering. Since the document key is guaranteed to be unique, no
|
|
more than a single document will match this filter. For other attributes this
|
|
may not be the case. To return a subset of active users (determined by an
|
|
attribute called *status*), sorted by name in ascending order, you can do:
|
|
|
|
```js
|
|
FOR doc IN users
|
|
FILTER doc.status == "active"
|
|
SORT doc.name
|
|
LIMIT 10
|
|
```
|
|
|
|
Note that operations do not have to occur in a fixed order and that their order
|
|
can influence the result significantly. Limiting the number of documents
|
|
before a filter is usually not what you want, because it easily misses a lot
|
|
of documents that would fulfill the filter criterion, but are ignored because
|
|
of a premature *LIMIT* clause. Because of the aforementioned reasons, *LIMIT*
|
|
is usually put at the very end, after *FILTER*, *SORT* and other operations.
|
|
|
|
See the [High Level Operations](Operations/README.md) chapter for more details.
|
|
|
|
Data Modification Queries
|
|
-------------------------
|
|
|
|
AQL supports the following data-modification operations:
|
|
|
|
- **INSERT**: insert new documents into a collection
|
|
- **UPDATE**: partially update existing documents in a collection
|
|
- **REPLACE**: completely replace existing documents in a collection
|
|
- **REMOVE**: remove existing documents from a collection
|
|
- **UPSERT**: conditionally insert or update documents in a collection
|
|
|
|
Below you find some simple example queries that use these operations.
|
|
The operations are detailed in the chapter [High Level Operations](Operations/README.md).
|
|
|
|
|
|
### Modifying a single document
|
|
|
|
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*:
|
|
|
|
```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.
|
|
|
|
```js
|
|
INSERT {
|
|
_key: "GilbertoGil",
|
|
firstName: "Gilberto",
|
|
name: "Gil",
|
|
city: "Fortalezza"
|
|
} IN users
|
|
```
|
|
|
|
As ArangoDB is schema-free, attributes of the documents may vary:
|
|
|
|
```js
|
|
INSERT {
|
|
_key: "PhilCarpenter",
|
|
firstName: "Phil",
|
|
name: "Carpenter",
|
|
middleName: "G.",
|
|
status: "inactive"
|
|
} 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
|
|
|
|
```js
|
|
UPDATE "PhilCarpenter" WITH {
|
|
status: "active",
|
|
location: "Beijing"
|
|
} IN users
|
|
```
|
|
|
|
Replace is an alternative to update where all attributes of the document are replaced.
|
|
|
|
```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 :
|
|
|
|
```js
|
|
REMOVE "GilbertoGil" IN users
|
|
```
|
|
|
|
or
|
|
|
|
```js
|
|
REMOVE { _key: "GilbertoGil" } IN users
|
|
```
|
|
|
|
### Modifying multiple documents
|
|
|
|
Data-modification operations are normally combined with *FOR* loops to
|
|
iterate over a given list of documents. They can optionally be combined with
|
|
*FILTER* statements and the like.
|
|
|
|
Let's start with an example that modifies existing documents in a collection
|
|
*users* that match some condition:
|
|
|
|
```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*:
|
|
|
|
```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:
|
|
|
|
```js
|
|
FOR u IN users
|
|
FILTER u.status == "deleted"
|
|
REMOVE u IN backup
|
|
```
|
|
|
|
### Returning documents
|
|
|
|
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:
|
|
|
|
```js
|
|
FOR i IN 1..100
|
|
INSERT { value: i } IN test
|
|
RETURN NEW
|
|
```
|
|
|
|
```js
|
|
FOR u IN users
|
|
FILTER u.status == "deleted"
|
|
REMOVE u IN users
|
|
RETURN OLD
|
|
```
|
|
|
|
```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
|
|
only refer to the `NEW` pseudo-value, and `REMOVE` operations only to `OLD`.
|
|
`UPDATE`, `REPLACE` and `UPSERT` 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.
|
|
|
|
#### Projections
|
|
|
|
It is possible to return a projection of the documents in `OLD` or `NEW` instead of
|
|
returning the entire documents. This can be used to reduce the amount of data returned
|
|
by queries.
|
|
|
|
For example, the following query will return only the keys of the inserted documents:
|
|
|
|
```js
|
|
FOR i IN 1..100
|
|
INSERT { value: i } IN test
|
|
RETURN NEW._key
|
|
```
|
|
|
|
#### 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:
|
|
|
|
```js
|
|
FOR u IN users
|
|
FILTER u.status == "not active"
|
|
UPDATE u WITH { status: "inactive" } IN users
|
|
RETURN { old: OLD, new: NEW }
|
|
```
|
|
|
|
#### Calculations with OLD or NEW
|
|
|
|
It is also possible to run additional calculations with `LET` statements between the
|
|
data-modification part and the final `RETURN` of an AQL query. For example, the following
|
|
query performs an upsert operation and returns whether an existing document was
|
|
updated, or a new document was inserted. It does so by checking the `OLD` variable
|
|
after the `UPSERT` and using a `LET` statement to store a temporary string for
|
|
the operation type:
|
|
|
|
```js
|
|
UPSERT { name: "test" }
|
|
INSERT { name: "test" }
|
|
UPDATE { } IN users
|
|
LET opType = IS_NULL(OLD) ? "insert" : "update"
|
|
RETURN { _key: NEW._key, type: opType }
|
|
```
|
|
|
|
### 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](../Manual/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
|
|
data in multiple collections with a single query. It is still possible (and
|
|
was shown above) to read from one or many collections and modify data in another
|
|
within the same query.
|
|
|
|
Only a single data-modification operation can be used per AQL query. Data-modification
|
|
queries cannot be used inside subqueries. Data-modification operations can optionally
|
|
be followed by `LET` operations and a single `RETURN` operation to return data. If
|
|
expressions are used within these operations, they cannot contain subqueries or
|
|
access data in collections using AQL functions.
|
|
|
|
Finally, data-modification operations can optionally be followed by `LET` and `RETURN`,
|
|
but not by other statements such as `SORT`, `COLLECT` etc.
|
|
|
|
|
|
### Transactional Execution
|
|
|
|
On a single server, data-modification operations are executed transactionally.
|
|
If a data-modification operation fails, any changes made by it will be rolled
|
|
back automatically as if they never happened.
|
|
|
|
In a cluster, AQL data-modification queries are currently not executed transactionally.
|
|
Additionally, *update*, *replace*, *upsert* and *remove* AQL queries currently
|
|
require the *_key* attribute to be specified for all documents that should be
|
|
modified or removed, even if a shared key attribute other than *_key* was chosen
|
|
for the collection. This restriction may be overcome in a future release of ArangoDB.
|