-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix docs for multiple mutation blocks (#4332)
- Loading branch information
1 parent
e8379f0
commit 8961a99
Showing
1 changed file
with
96 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -852,32 +852,43 @@ cat data.json | jq '{set: .}' | |
## Upsert Block | ||
|
||
The upsert block allows performing queries and mutations in a single request. The upsert | ||
block contains one query block and one mutation block. Variables defined in the query | ||
block can be used in the mutation block using the `uid` function. | ||
Support for `val` function is coming soon. | ||
block contains one query block and one or more than one mutation blocks. Variables defined | ||
in the query block can be used in the mutation blocks using the `uid` and `val` function. | ||
|
||
In general, the structure of the upsert block is as follows: | ||
|
||
``` | ||
upsert { | ||
query <query block> | ||
[fragment <fragment block>] | ||
mutation <mutation block> | ||
mutation <mutation block 1> | ||
[mutation <mutation block 2>] | ||
... | ||
} | ||
``` | ||
|
||
The Mutation block currently only allows the `uid` function, which allows extracting UIDs | ||
from variables defined in the query block. There are two possible outcomes based on the | ||
results of executing the query block: | ||
Execution of an upsert block also returns the response of the query executed on the state | ||
of the database *before mutation was executed*. To get the latest result, we should commit | ||
the mutation and execute another query. | ||
|
||
### `uid` Function | ||
|
||
The `uid` function allows extracting UIDs from variables defined in the query block. | ||
There are two possible outcomes based on the results of executing the query block: | ||
|
||
* If the variable is empty i.e. no node matched the query, the `uid` function returns a new UID in case of a `set` operation and is thus treated similar to a blank node. On the other hand, for `delete/del` operation, it returns no UID, and thus the operation becomes a no-op and is silently ignored. A blank node gets the same UID across all the mutation blocks. | ||
* If the variable stores one or more than one UIDs, the `uid` function returns all the UIDs stored in the variable. In this case, the operation is performed on all the UIDs returned, one at a time. | ||
|
||
Execution of an upsert block also returns the response of the query executed on the state | ||
of the database *before mutation was executed*. To get the latest result, we should commit | ||
the mutation and execute another query. | ||
### `val` Function | ||
|
||
### Example | ||
The `val` function allows extracting values from value variables. Value variables store | ||
a mapping from UIDs to their corresponding values. Hence, `val(v)` is replaced by the value | ||
stored in the mapping for the UID (Subject) in the N-Quad. If the variable `v` has no value | ||
for a given UID, the mutation is silently ignored. The `val` function can be used with the | ||
result of aggregate variables as well, in which case, all the UIDs in the mutation would | ||
be updated with the aggregate value. | ||
|
||
### Example of `uid` Function | ||
|
||
Consider an example with the following schema: | ||
|
||
|
@@ -903,6 +914,7 @@ upsert { | |
query { | ||
q(func: eq(email, "[email protected]")) { | ||
v as uid | ||
name | ||
} | ||
} | ||
|
@@ -938,15 +950,16 @@ the information is updated. If the user doesn't exist, `uid(v)` is treated | |
as a blank node and a new user is created as explained above. | ||
|
||
If we run the same mutation again, the data would just be overwritten, and no new uid is | ||
created. Note that the `uids` map is empty in the response when the mutation is executed | ||
again and the query response (key `q`) contains the uid that was created in the previous upsert. | ||
created. Note that the `uids` map is empty in the result when the mutation is executed | ||
again and the `data` map (key `q`) contains the uid that was created in the previous upsert. | ||
|
||
```json | ||
{ | ||
"data": { | ||
"q": [ | ||
{ | ||
"uid": "0x1" | ||
"uid": "0x1", | ||
"name": "first last" | ||
} | ||
], | ||
"code": "Success", | ||
|
@@ -962,7 +975,7 @@ We can achieve the same result using `json` dataset as follows: | |
```sh | ||
curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d ' | ||
{ | ||
"query": "{ q(func: eq(email, "[email protected]")) {v as uid} }", | ||
"query": "{ q(func: eq(email, \\"[email protected]\\")) {v as uid\\n name} }", | ||
"set": { | ||
"uid": "uid(v)", | ||
"name": "first last", | ||
|
@@ -1016,9 +1029,9 @@ user by extracting the uid from the variable `v` using `uid` function. | |
We can achieve the same result using `json` dataset as follows: | ||
|
||
```sh | ||
curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d ' | ||
curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d $' | ||
{ | ||
"query": "{ q(func: eq(email, "[email protected]")) {v as uid} }", | ||
"query": "{ q(func: eq(email, \\"[email protected]\\")) {v as uid} }", | ||
"set":{ | ||
"uid": "uid(v)", | ||
"age": "28" | ||
|
@@ -1029,22 +1042,28 @@ curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow | |
If we want to execute the mutation only when the user exists, we could use | ||
[Conditional Upsert]({{< relref "#conditional-upsert" >}}). | ||
|
||
### Bulk Delete Example | ||
### Example of `val` Function | ||
|
||
Let's say we want to delete all the users of `company1` from the database. This can be | ||
achieved in just one query using the upsert block: | ||
Let's say we want to migrate the predicate `age` to `other`. We can do this using the | ||
following mutation: | ||
|
||
```sh | ||
curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true -d $' | ||
upsert { | ||
query { | ||
v as var(func: regexp(email, /.*@company1.io$/)) | ||
v as var(func: has(age)) { | ||
a as age | ||
} | ||
} | ||
mutation { | ||
# we copy the values from the old predicate | ||
set { | ||
uid(v) <other> val(a) . | ||
} | ||
# and we delete the old predicate | ||
delete { | ||
uid(v) <name> * . | ||
uid(v) <email> * . | ||
uid(v) <age> * . | ||
} | ||
} | ||
|
@@ -1064,10 +1083,52 @@ Result: | |
} | ||
``` | ||
|
||
Here, variable `a` will store a mapping from all the UIDs to their `age`. The mutation | ||
block then stores the corresponding value of `age` for each UID in the `other` predicate | ||
and deletes the `age` predicate. | ||
|
||
We can achieve the same result using `json` dataset as follows: | ||
|
||
```sh | ||
curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d $'{ | ||
"query": "{ v as var(func: regexp(email, /.*@company1.io$/)) }", | ||
"delete": { | ||
"uid": "uid(v)", | ||
"age": null | ||
}, | ||
"set": { | ||
"uid": "uid(v)", | ||
"other": "val(a)" | ||
} | ||
}' | jq | ||
``` | ||
|
||
### Bulk Delete Example | ||
|
||
Let's say we want to delete all the users of `company1` from the database. This can be | ||
achieved in just one query using the upsert block as follows: | ||
|
||
```sh | ||
curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true -d $' | ||
upsert { | ||
query { | ||
v as var(func: regexp(email, /.*@company1.io$/)) | ||
} | ||
mutation { | ||
delete { | ||
uid(v) <name> * . | ||
uid(v) <email> * . | ||
uid(v) <age> * . | ||
} | ||
} | ||
}' | jq | ||
``` | ||
|
||
We can achieve the same result using `json` dataset as follows: | ||
|
||
```sh | ||
curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d '{ | ||
"query": "{ v as var(func: regexp(email, /.*@company1.io$/)) }", | ||
"delete": { | ||
"uid": "uid(v)", | ||
|
@@ -1080,7 +1141,7 @@ curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow | |
|
||
## Conditional Upsert | ||
|
||
The upsert block also allows specifying a conditional mutation block using an `@if` | ||
The upsert block also allows specifying conditional mutation blocks using an `@if` | ||
directive. The mutation is executed only when the specified condition is true. If the | ||
condition is false, the mutation is silently ignored. The general structure of | ||
Conditional Upsert looks like as follows: | ||
|
@@ -1089,21 +1150,23 @@ Conditional Upsert looks like as follows: | |
upsert { | ||
query <query block> | ||
[fragment <fragment block>] | ||
mutation @if(<condition>) <mutation block> | ||
mutation [@if(<condition>)] <mutation block 1> | ||
[mutation [@if(<condition>)] <mutation block 2>] | ||
... | ||
} | ||
``` | ||
|
||
The `@if` directive accepts a condition on variables defined in the query block and can be | ||
connected using `AND`, `OR` and `NOT`. | ||
|
||
### Example | ||
### Example of Conditional Upsert | ||
|
||
Let's say in our previous example, we know the `company1` has less than 100 employees. | ||
For safety, we want the mutation to execute only when the variable `v` stores less than | ||
100 but greater than 50 UIDs in it. This can be achieved as follows: | ||
|
||
```sh | ||
curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true -d $' | ||
curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true -d $' | ||
upsert { | ||
query { | ||
v as var(func: regexp(email, /.*@company1.io$/)) | ||
|
@@ -1134,16 +1197,7 @@ curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow | |
}' | jq | ||
``` | ||
|
||
|
||
### Multiple Mutation Block | ||
|
||
The upsert block supports multiple mutation blocks within an upsert block. Each mutation | ||
block can optionally have condition (using `@if`) specified as well. A mutation block | ||
is executed only when the corresponding condition is evaluated to true. This feature | ||
along with the support of conditional upsert provides the equivalent support of | ||
`if..else` in an upsert block. | ||
|
||
### Example | ||
### Example of Multiple Mutation Blocks | ||
|
||
Consider an example with the following schema: | ||
|
||
|
@@ -1154,10 +1208,10 @@ curl localhost:8080/alter -X POST -d $' | |
``` | ||
|
||
Let's say, we have many users stored in our database each having one or more than | ||
one email IDs. Now, we get two email IDs that belong to the same user. If the email IDs | ||
belong to the different nodes in the database, we want to delete the existing nodes and | ||
create a new node with both the emails attached to this new node. Otherwise, we | ||
create/update the new/existing node with both the emails. | ||
one email Addresses. Now, we get two email Addresses that belong to the same user. | ||
If the email Addresses belong to the different nodes in the database, we want to delete | ||
the existing nodes and create a new node with both the emails attached to this new node. | ||
Otherwise, we create/update the new/existing node with both the emails. | ||
|
||
```sh | ||
curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true -d $' | ||
|
@@ -1284,7 +1338,7 @@ Result (when both emails exist and are already attached to the same node): | |
We can achieve the same result using `json` dataset as follows: | ||
|
||
```sh | ||
curl -H "Content-Type: application/json" -X POST localhost:8180/mutate?commitNow=true -d '{ | ||
curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d '{ | ||
"query": "{q1(func: eq(email, \"[email protected]\")) @filter(not(eq(email, \"[email protected]\"))) {u1 as uid} \n q2(func: eq(email, \"[email protected]\")) @filter(not(eq(email, \"[email protected]\"))) {u2 as uid} \n q3(func: eq(email, \"[email protected]\")) @filter(eq(email, \"[email protected]\")) {u3 as uid}}", | ||
"mutations": [ | ||
{ | ||
|