github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/wiki/content/mutations/index.md (about) 1 +++ 2 title = "Mutations" 3 +++ 4 5 Adding or removing data in Dgraph is called a mutation. 6 7 A mutation that adds triples is done with the `set` keyword. 8 ``` 9 { 10 set { 11 # triples in here 12 } 13 } 14 ``` 15 16 ## Triples 17 18 The input language is triples in the W3C standard [RDF N-Quad format](https://www.w3.org/TR/n-quads/). 19 20 Each triple has the form 21 ``` 22 <subject> <predicate> <object> . 23 ``` 24 Meaning that the graph node identified by `subject` is linked to `object` with directed edge `predicate`. Each triple ends with a period. The subject of a triple is always a node in the graph, while the object may be a node or a value (a literal). 25 26 For example, the triple 27 ``` 28 <0x01> <name> "Alice" . 29 ``` 30 Represents that graph node with ID `0x01` has a `name` with string value `"Alice"`. While triple 31 ``` 32 <0x01> <friend> <0x02> . 33 ``` 34 Represents that graph node with ID `0x01` is linked with the `friend` edge to node `0x02`. 35 36 Dgraph creates a unique 64 bit identifier for every blank node in the mutation - the node's UID. A mutation can include a blank node as an identifier for the subject or object, or a known UID from a previous mutation. 37 38 39 ## Blank Nodes and UID 40 41 Blank nodes in mutations, written `_:identifier`, identify nodes within a mutation. Dgraph creates a UID identifying each blank node and returns the created UIDs as the mutation result. For example, mutation: 42 43 ``` 44 { 45 set { 46 _:class <student> _:x . 47 _:class <student> _:y . 48 _:class <name> "awesome class" . 49 _:x <name> "Alice" . 50 _:x <planet> "Mars" . 51 _:x <friend> _:y . 52 _:y <name> "Bob" . 53 } 54 } 55 ``` 56 results in output (the actual UIDs will be different on any run of this mutation) 57 ``` 58 { 59 "data": { 60 "code": "Success", 61 "message": "Done", 62 "uids": { 63 "class": "0x2712", 64 "x": "0x2713", 65 "y": "0x2714" 66 } 67 } 68 } 69 ``` 70 The graph has thus been updated as if it had stored the triples 71 ``` 72 <0x6bc818dc89e78754> <student> <0xc3bcc578868b719d> . 73 <0x6bc818dc89e78754> <student> <0xb294fb8464357b0a> . 74 <0x6bc818dc89e78754> <name> "awesome class" . 75 <0xc3bcc578868b719d> <name> "Alice" . 76 <0xc3bcc578868b719d> <planet> "Mars" . 77 <0xc3bcc578868b719d> <friend> <0xb294fb8464357b0a> . 78 <0xb294fb8464357b0a> <name> "Bob" . 79 ``` 80 The blank node labels `_:class`, `_:x` and `_:y` do not identify the nodes after the mutation, and can be safely reused to identify new nodes in later mutations. 81 82 A later mutation can update the data for existing UIDs. For example, the following to add a new student to the class. 83 ``` 84 { 85 set { 86 <0x6bc818dc89e78754> <student> _:x . 87 _:x <name> "Chris" . 88 } 89 } 90 ``` 91 92 A query can also directly use UID. 93 ``` 94 { 95 class(func: uid(0x6bc818dc89e78754)) { 96 name 97 student { 98 name 99 planet 100 friend { 101 name 102 } 103 } 104 } 105 } 106 ``` 107 108 ## External IDs 109 110 Dgraph's input language, RDF, also supports triples of the form `<a_fixed_identifier> <predicate> literal/node` and variants on this, where the label `a_fixed_identifier` is intended as a unique identifier for a node. For example, mixing [schema.org](http://schema.org) identifiers, [the movie database](https://www.themoviedb.org/) identifiers and blank nodes: 111 112 ``` 113 _:userA <http://schema.org/type> <http://schema.org/Person> . 114 _:userA <http://schema.org/name> "FirstName LastName" . 115 <https://www.themoviedb.org/person/32-robin-wright> <http://schema.org/type> <http://schema.org/Person> . 116 <https://www.themoviedb.org/person/32-robin-wright> <http://schema.org/name> "Robin Wright" . 117 ``` 118 119 As Dgraph doesn't natively support such external IDs as node identifiers. Instead, external IDs can be stored as properties of a node with an `xid` edge. For example, from the above, the predicate names are valid in Dgraph, but the node identified with `<http://schema.org/Person>` could be identified in Dgraph with a UID, say `0x123`, and an edge 120 121 ``` 122 <0x123> <xid> "http://schema.org/Person" . 123 ``` 124 125 While Robin Wright might get UID `0x321` and triples 126 127 ``` 128 <0x321> <xid> "https://www.themoviedb.org/person/32-robin-wright" . 129 <0x321> <http://schema.org/type> <0x123> . 130 <0x321> <http://schema.org/name> "Robin Wright" . 131 ``` 132 133 An appropriate schema might be as follows. 134 ``` 135 xid: string @index(exact) . 136 <http://schema.org/type>: [uid] @reverse . 137 ``` 138 139 Query Example: All people. 140 141 ``` 142 { 143 var(func: eq(xid, "http://schema.org/Person")) { 144 allPeople as <~http://schema.org/type> 145 } 146 147 q(func: uid(allPeople)) { 148 <http://schema.org/name> 149 } 150 } 151 ``` 152 153 Query Example: Robin Wright by external ID. 154 155 ``` 156 { 157 robin(func: eq(xid, "https://www.themoviedb.org/person/32-robin-wright")) { 158 expand(_all_) { expand(_all_) } 159 } 160 } 161 162 ``` 163 164 {{% notice "note" %}} `xid` edges are not added automatically in mutations. In general it is a user's responsibility to check for existing `xid`'s and add nodes and `xid` edges if necessary. Dgraph leaves all checking of uniqueness of such `xid`'s to external processes. {{% /notice %}} 165 166 ## External IDs and Upsert Block 167 168 The upsert block makes managing external IDs easy. 169 170 Set the schema. 171 ``` 172 xid: string @index(exact) . 173 <http://schema.org/name>: string @index(exact) . 174 <http://schema.org/type>: [uid] @reverse . 175 ``` 176 177 Set the type first of all. 178 ``` 179 { 180 set { 181 _:blank <xid> "http://schema.org/Person" . 182 } 183 } 184 ``` 185 186 Now you can create a new person and attach its type using the upsert block. 187 ``` 188 upsert { 189 query { 190 var(func: eq(xid, "http://schema.org/Person")) { 191 Type as uid 192 } 193 var(func: eq(<http://schema.org/name>, "Robin Wright")) { 194 Person as uid 195 } 196 } 197 mutation { 198 set { 199 uid(Person) <xid> "https://www.themoviedb.org/person/32-robin-wright" . 200 uid(Person) <http://schema.org/type> uid(Type) . 201 uid(Person) <http://schema.org/name> "Robin Wright" . 202 } 203 } 204 } 205 ``` 206 207 You can also delete a person and detach the relation between Type and Person Node. It's the same as above, but you use the keyword "delete" instead of "set". "`http://schema.org/Person`" will remain but "`Robin Wright`" will be deleted. 208 209 ``` 210 upsert { 211 query { 212 var(func: eq(xid, "http://schema.org/Person")) { 213 Type as uid 214 } 215 var(func: eq(<http://schema.org/name>, "Robin Wright")) { 216 Person as uid 217 } 218 } 219 mutation { 220 delete { 221 uid(Person) <xid> "https://www.themoviedb.org/person/32-robin-wright" . 222 uid(Person) <http://schema.org/type> uid(Type) . 223 uid(Person) <http://schema.org/name> "Robin Wright" . 224 } 225 } 226 } 227 ``` 228 229 Query by user. 230 ``` 231 { 232 q(func: eq(<http://schema.org/name>, "Robin Wright")) { 233 uid 234 xid 235 <http://schema.org/name> 236 <http://schema.org/type> { 237 uid 238 xid 239 } 240 } 241 } 242 ``` 243 244 ## Language and RDF Types 245 246 RDF N-Quad allows specifying a language for string values and an RDF type. Languages are written using `@lang`. For example 247 ``` 248 <0x01> <name> "Adelaide"@en . 249 <0x01> <name> "Аделаида"@ru . 250 <0x01> <name> "Adélaïde"@fr . 251 ``` 252 See also [how language strings are handled in queries]({{< relref "query-language/index.md#language-support" >}}). 253 254 RDF types are attached to literals with the standard `^^` separator. For example 255 ``` 256 <0x01> <age> "32"^^<xs:int> . 257 <0x01> <birthdate> "1985-06-08"^^<xs:dateTime> . 258 ``` 259 260 The supported [RDF datatypes](https://www.w3.org/TR/rdf11-concepts/#section-Datatypes) and the corresponding internal type in which the data is stored are as follows. 261 262 | Storage Type | Dgraph type | 263 | ------------- | :------------: | 264 | <xs:string> | `string` | 265 | <xs:dateTime> | `dateTime` | 266 | <xs:date> | `datetime` | 267 | <xs:int> | `int` | 268 | <xs:boolean> | `bool` | 269 | <xs:double> | `float` | 270 | <xs:float> | `float` | 271 | <geo:geojson> | `geo` | 272 | <xs:password> | `password` | 273 | <http://www.w3.org/2001/XMLSchema#string> | `string` | 274 | <http://www.w3.org/2001/XMLSchema#dateTime> | `dateTime` | 275 | <http://www.w3.org/2001/XMLSchema#date> | `dateTime` | 276 | <http://www.w3.org/2001/XMLSchema#int> | `int` | 277 | <http://www.w3.org/2001/XMLSchema#boolean> | `bool` | 278 | <http://www.w3.org/2001/XMLSchema#double> | `float` | 279 | <http://www.w3.org/2001/XMLSchema#float> | `float` | 280 281 282 See the section on [RDF schema types]({{< relref "#rdf-types" >}}) to understand how RDF types affect mutations and storage. 283 284 285 ## Batch mutations 286 287 Each mutation may contain multiple RDF triples. For large data uploads many such mutations can be batched in parallel. The command `dgraph live` does just this; by default batching 1000 RDF lines into a query, while running 100 such queries in parallel. 288 289 `dgraph live` takes as input gzipped N-Quad files (that is triple lists without `{ set {`) and batches mutations for all triples in the input. The tool has documentation of options. 290 291 ``` 292 dgraph live --help 293 ``` 294 See also [Fast Data Loading](/deploy#fast-data-loading). 295 296 ## Delete 297 298 A delete mutation, signified with the `delete` keyword, removes triples from the store. 299 300 For example, if the store contained 301 ``` 302 <0xf11168064b01135b> <name> "Lewis Carrol" 303 <0xf11168064b01135b> <died> "1998" 304 ``` 305 306 Then delete mutation 307 308 ``` 309 { 310 delete { 311 <0xf11168064b01135b> <died> "1998" . 312 } 313 } 314 ``` 315 316 Deletes the erroneous data and removes it from indexes if present. 317 318 For a particular node `N`, all data for predicate `P` (and corresponding indexing) is removed with the pattern `S P *`. 319 320 ``` 321 { 322 delete { 323 <0xf11168064b01135b> <author.of> * . 324 } 325 } 326 ``` 327 328 The pattern `S * *` deletes all known edges out of a node (the node itself may 329 remain as the target of edges), any reverse edges corresponding to the removed 330 edges and any indexing for the removed data. The predicates to delete are 331 derived from the type information for that node (the value of the `dgraph.type` 332 edges on that node and their corresponding definitions in the schema). If that 333 information is missing, this operation will be a no-op. 334 335 ``` 336 { 337 delete { 338 <0xf11168064b01135b> * * . 339 } 340 } 341 ``` 342 343 344 {{% notice "note" %}} The patterns `* P O` and `* * O` are not supported since its expensive to store/find all the incoming edges. {{% /notice %}} 345 346 ### Deletion of non-list predicates 347 348 Deleting the value of a non-list predicate (i.e a 1-to-1 relation) can be done in two ways. 349 350 1. Using the star notation mentioned in the last section. 351 1. Setting the object to a specific value. If the value passed is not the current value, the mutation will succeed but will have no effect. If the value passed is the current value, the mutation will succeed and will delete the triple. 352 353 For language-tagged values, the following special syntax is supported: 354 355 ``` 356 { 357 delete { 358 <0x12345> <name@es> * . 359 } 360 } 361 ``` 362 363 In this example, the value of name tagged with language tag `es` will be deleted. 364 Other tagged values are left untouched. 365 366 ## Mutations using cURL 367 368 Mutations can be done over HTTP by making a `POST` request to an Alpha's `/mutate` endpoint. On the command line this can be done with curl. To commit the mutation, pass the parameter `commitNow=true` in the URL. 369 370 To run a `set` mutation: 371 372 ```sh 373 curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true -d $' 374 { 375 set { 376 _:alice <name> "Alice" . 377 } 378 }' 379 ``` 380 381 To run a `delete` mutation: 382 383 ```sh 384 curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true -d $' 385 { 386 delete { 387 # Example: The UID of Alice is 0x56f33 388 <0x56f33> <name> * . 389 } 390 }' 391 ``` 392 393 To run an RDF mutation stored in a file, use curl's `--data-binary` option so that, unlike the `-d` option, the data is not URL encoded. 394 395 ```sh 396 curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true --data-binary @mutation.txt 397 ``` 398 399 ## JSON Mutation Format 400 401 Mutations can also be specified using JSON objects. This can allow mutations to 402 be expressed in a more natural way. It also eliminates the need for apps to 403 have custom serialisation code, since most languages already have a JSON 404 marshalling library. 405 406 When Dgraph receives a mutation as a JSON object, it first converts in into 407 multiple RDFs that are then processed as normal. 408 409 Each JSON object represents a single node in the graph. 410 411 {{% notice "note" %}} 412 JSON mutations are available via gRPC clients such as the Go client, JS client, and Java client, and are available to HTTP clients with [dgraph-js-http](https://github.com/dgraph-io/dgraph-js-http) and cURL. See more about cURL [here]({{< relref "#using-json-operations-via-curl" >}}) 413 {{% /notice %}} 414 415 ### Setting literal values 416 417 When setting new values, the `set_json` field in the `Mutation` message should 418 contain a JSON object. 419 420 Literal values can be set by adding a key/value to the JSON object. The key 421 represents the predicate, and the value represents the object. 422 423 For example: 424 ```json 425 { 426 "name": "diggy", 427 "food": "pizza" 428 } 429 ``` 430 Will be converted into the RDFs: 431 ``` 432 _:blank-0 <name> "diggy" . 433 _:blank-0 <food> "pizza" . 434 ``` 435 436 The result of the mutation would also contain a map, which would have the uid assigned corresponding 437 to the key `blank-0`. You could specify your own key like 438 439 ```json 440 { 441 "uid": "_:diggy", 442 "name": "diggy", 443 "food": "pizza" 444 } 445 ``` 446 447 In this case, the assigned uids map would have a key called `diggy` with the value being the uid 448 assigned to it. 449 450 ### Language support 451 452 An important difference between RDF and JSON mutations is in regards to specifying a string value's 453 language. In JSON, the language tag is appended to the edge _name_, not the value like in RDF. 454 455 For example, the JSON mutation 456 ```json 457 { 458 "food": "taco", 459 "rating@en": "tastes good", 460 "rating@es": "sabe bien", 461 "rating@fr": "c'est bon", 462 "rating@it": "è buono" 463 } 464 ``` 465 466 is equivalent to the following RDF: 467 ``` 468 _:blank-0 <food> "taco" . 469 _:blank-0 <rating> "tastes good"@en . 470 _:blank-0 <rating> "sabe bien"@es . 471 _:blank-0 <rating> "c'est bon"@fr . 472 _:blank-0 <rating> "è buono"@it . 473 ``` 474 475 ### Geolocation support 476 477 Support for geolocation data is available in JSON. Geo-location data is entered 478 as a JSON object with keys "type" and "coordinates". Keep in mind we only 479 support indexing on the Point, Polygon, and MultiPolygon types, but we can store 480 other types of geolocation data. Below is an example: 481 482 ``` 483 { 484 "food": "taco", 485 location: { 486 "type": "Point", 487 "coordinates": [1.0, 2.0] 488 } 489 } 490 ``` 491 492 ### Referencing existing nodes 493 494 If a JSON object contains a field named `"uid"`, then that field is interpreted 495 as the UID of an existing node in the graph. This mechanism allows you to 496 reference existing nodes. 497 498 For example: 499 ```json 500 { 501 "uid": "0x467ba0", 502 "food": "taco", 503 "rating": "tastes good", 504 } 505 ``` 506 Will be converted into the RDFs: 507 ``` 508 <0x467ba0> <food> "taco" . 509 <0x467ba0> <rating> "tastes good" . 510 ``` 511 512 ### Edges between nodes 513 514 Edges between nodes are represented in a similar way to literal values, except 515 that the object is a JSON object. 516 517 For example: 518 ```json 519 { 520 "name": "Alice", 521 "friend": { 522 "name": "Betty" 523 } 524 } 525 ``` 526 Will be converted into the RDFs: 527 ``` 528 _:blank-0 <name> "Alice" . 529 _:blank-0 <friend> _:blank-1 . 530 _:blank-1 <name> "Betty" . 531 ``` 532 533 The result of the mutation would contain the uids assigned to `blank-0` and `blank-1` nodes. If you 534 wanted to return these uids under a different key, you could specify the `uid` field as a blank 535 node. 536 537 ```json 538 { 539 "uid": "_:alice", 540 "name": "Alice", 541 "friend": { 542 "uid": "_:bob", 543 "name": "Betty" 544 } 545 } 546 ``` 547 Will be converted to: 548 ``` 549 _:alice <name> "Alice" . 550 _:alice <friend> _:bob . 551 _:bob <name> "Betty" . 552 ``` 553 554 Existing nodes can be referenced in the same way as when adding literal values. 555 E.g. to link two existing nodes: 556 ```json 557 { 558 "uid": "0x123", 559 "link": { 560 "uid": "0x456" 561 } 562 } 563 ``` 564 565 Will be converted to: 566 567 ```JSON 568 <0x123> <link> <0x456> . 569 ``` 570 571 {{% notice "note" %}} 572 A common mistake is to attempt to use `{"uid":"0x123","link":"0x456"}`. This 573 will result in an error. Dgraph interprets this JSON object as setting the 574 `link` predicate to the string`"0x456"`, which is usually not intended. {{% 575 /notice %}} 576 577 ### Deleting literal values 578 579 Deletion mutations can also be sent in JSON format. To send a delete mutation, 580 use the `delete_json` field instead of the `set_json` field in the `Mutation` 581 message. 582 583 {{% notice "note" %}} Check the [JSON Syntax using Raw HTTP or Ratel UI]({{< relref "#json-syntax-using-raw-http-or-ratel-ui">}}) section if you're using the dgraph-js-http client or Ratel UI. {{% /notice %}} 584 585 When using delete mutations, an existing node always has to be referenced. So 586 the `"uid"` field for each JSON object must be present. Predicates that should 587 be deleted should be set to the JSON value `null`. 588 589 For example, to remove a food rating: 590 ```json 591 { 592 "uid": "0x467ba0", 593 "rating": null 594 } 595 ``` 596 597 ### Deleting edges 598 599 Deleting a single edge requires the same JSON object that would create that 600 edge. E.g. to delete the predicate `link` from `"0x123"` to `"0x456"`: 601 ```json 602 { 603 "uid": "0x123", 604 "link": { 605 "uid": "0x456" 606 } 607 } 608 ``` 609 610 All edges for a predicate emanating from a single node can be deleted at once 611 (corresponding to deleting `S P *`): 612 ```json 613 { 614 "uid": "0x123", 615 "link": null 616 } 617 ``` 618 619 If no predicates are specified, then all of the node's known outbound edges (to 620 other nodes and to literal values) are deleted (corresponding to deleting `S * 621 *`). The predicates to delete are derived using the type system. Refer to the 622 [RDF format]({{< relref "#delete" >}}) documentation and the section on the 623 [type system]({{< relref "query-language/index.md#type-system" >}}) for more 624 information: 625 626 ```json 627 { 628 "uid": "0x123" 629 } 630 ``` 631 632 ### Facets 633 634 Facets can be created by using the `|` character to separate the predicate 635 and facet key in a JSON object field name. This is the same encoding schema 636 used to show facets in query results. E.g. 637 ```json 638 { 639 "name": "Carol", 640 "name|initial": "C", 641 "friend": { 642 "name": "Daryl", 643 "friend|close": "yes" 644 } 645 } 646 ``` 647 Produces the following RDFs: 648 ``` 649 _:blank-0 <name> "Carol" (initial=C) . 650 _:blank-0 <friend> _:blank-1 (close=yes) . 651 _:blank-1 <name> "Daryl" . 652 ``` 653 654 ### Creating a list with JSON and interacting with 655 656 Schema: 657 658 ```JSON 659 testList: [string] . 660 ``` 661 662 ```JSON 663 { 664 "testList": [ 665 "Grape", 666 "Apple", 667 "Strawberry", 668 "Banana", 669 "watermelon" 670 ] 671 } 672 ``` 673 674 Let’s then remove "Apple" from this list (Remember, it’s case sensitive): 675 676 ```JSON 677 { 678 "uid": "0xd", #UID of the list. 679 "testList": "Apple" 680 } 681 ``` 682 683 {{% notice "note" %}} Check the [JSON Syntax using Raw HTTP or Ratel UI]({{< relref "#json-syntax-using-raw-http-or-ratel-ui">}}) section if you're using the dgraph-js-http client or Ratel UI. {{% /notice %}} 684 685 686 Add another fruit: 687 688 ```JSON 689 { 690 "uid": "0xd", #UID of the list. 691 "testList": "Pineapple" 692 } 693 ``` 694 695 ### Specifying multiple operations 696 697 When specifying add or delete mutations, multiple nodes can be specified 698 at the same time using JSON arrays. 699 700 For example, the following JSON object can be used to add two new nodes, each 701 with a `name`: 702 703 ```JSON 704 [ 705 { 706 "name": "Edward" 707 }, 708 { 709 "name": "Fredric" 710 } 711 ] 712 ``` 713 714 ### JSON Syntax using Raw HTTP or Ratel UI 715 716 This syntax can be used in the most current version of Ratel, in the [dgraph-js-http](https://github.com/dgraph-io/dgraph-js-http) client or even via cURL. 717 718 You can also [download the Ratel UI for Linux, macOS, or Windows](https://discuss.dgraph.io/t/ratel-installer-for-linux-macos-and-windows-preview-version-ratel-update-from-v1-0-6/2884/). 719 720 Mutate: 721 ```JSON 722 { 723 "set": [ 724 { 725 # One JSON obj in here 726 }, 727 { 728 # Another JSON obj in here for multiple operations 729 } 730 ] 731 } 732 ``` 733 734 Delete: 735 736 Deletion operations are the same as [Deleting literal values]({{< relref "#deleting-literal-values">}}) and [Deleting edges]({{< relref "#deleting-edges">}}). 737 738 ```JSON 739 { 740 "delete": [ 741 { 742 # One JSON obj in here 743 }, 744 { 745 # Another JSON obj in here for multiple operations 746 } 747 ] 748 } 749 ``` 750 751 ### Using JSON operations via cURL 752 753 First you have to configure the HTTP header to specify content-type. 754 755 ```sh 756 -H 'Content-Type: application/json' 757 ``` 758 759 {{% notice "note" %}} 760 In order to use `jq` for JSON formatting you need the `jq` package. See the 761 [`jq` downloads](https://stedolan.github.io/jq/download/) page for installation 762 details. You can also use Python's built in `json.tool` module with `python -m 763 json.tool` to do JSON formatting. 764 {{% /notice %}} 765 766 ```sh 767 curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d $' 768 { 769 "set": [ 770 { 771 "name": "Alice" 772 }, 773 { 774 "name": "Bob" 775 } 776 ] 777 }' | jq 778 779 ``` 780 781 To delete: 782 783 ```sh 784 curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d $' 785 { 786 "delete": [ 787 { 788 "uid": "0xa" 789 } 790 ] 791 }' | jq 792 ``` 793 794 Mutation with a JSON file: 795 796 ```sh 797 curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d @data.json 798 ``` 799 800 where the contents of data.json looks like the following: 801 802 ```json 803 { 804 "set": [ 805 { 806 "name": "Alice" 807 }, 808 { 809 "name": "Bob" 810 } 811 ] 812 } 813 ``` 814 815 The JSON file must follow the same format for mutations over HTTP: a single JSON 816 object with the `"set"` or `"delete"` key and an array of JSON objects for the 817 mutation. If you already have a file with an array of data, you can use `jq` to 818 transform your data to the proper format. For example, if your data.json file 819 looks like this: 820 821 ```json 822 [ 823 { 824 "name": "Alice" 825 }, 826 { 827 "name": "Bob" 828 } 829 ] 830 ``` 831 832 then you can transform your data to the proper format with the following `jq` 833 command, where the `.` in the `jq` string represents the contents of data.json: 834 835 ```sh 836 cat data.json | jq '{set: .}' 837 ``` 838 839 ``` 840 { 841 "set": [ 842 { 843 "name": "Alice" 844 }, 845 { 846 "name": "Bob" 847 } 848 ] 849 } 850 ``` 851 852 ## Upsert Block 853 854 The upsert block allows performing queries and mutations in a single request. The upsert 855 block contains one query block and one mutation block. Variables defined in the query 856 block can be used in the mutation block using the `uid` function. 857 Support for `val` function is coming soon. 858 859 In general, the structure of the upsert block is as follows: 860 861 ``` 862 upsert { 863 query <query block> 864 [fragment <fragment block>] 865 mutation <mutation block> 866 } 867 ``` 868 869 The Mutation block currently only allows the `uid` function, which allows extracting UIDs 870 from variables defined in the query block. There are two possible outcomes based on the 871 results of executing the query block: 872 873 * 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. 874 * 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. 875 876 ### Example 877 878 Consider an example with the following schema: 879 880 ```sh 881 curl localhost:8080/alter -X POST -d $' 882 name: string @index(term) . 883 email: string @index(exact, trigram) @upsert . 884 age: int @index(int) . 885 ' | jq 886 ``` 887 888 Now, let's say we want to create a new user with `email` and `name` information. 889 We also want to make sure that one email has exactly one corresponding user in 890 the database. To achieve this, we need to first query whether a user exists 891 in the database with the given email. If a user exists, we use its UID 892 to update the `name` information. If the user doesn't exist, we create 893 a new user and update the `email` and `name` information. 894 895 We can do this using the upsert block as follows: 896 897 ```sh 898 curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true -d $' 899 upsert { 900 query { 901 v as var(func: eq(email, "user@company1.io")) 902 } 903 904 mutation { 905 set { 906 uid(v) <name> "first last" . 907 uid(v) <email> "user@company1.io" . 908 } 909 } 910 } 911 ' | jq 912 ``` 913 914 Result: 915 916 ```json 917 { 918 "data": { 919 "code": "Success", 920 "message": "Done", 921 "uids": { 922 "uid(v)": "0x2" 923 } 924 }, 925 "extensions": {...} 926 } 927 ``` 928 929 The query part of the upsert block stores the UID of the user with the provided email 930 in the variable `v`. The mutation part then extracts the UID from variable `v`, and 931 stores the `name` and `email` information in the database. If the user exists, 932 the information is updated. If the user doesn't exist, `uid(v)` is treated 933 as a blank node and a new user is created as explained above. 934 935 If we run the same mutation again, the data would just be overwritten, and no new uid is 936 created. Note that the `uids` map is empty in the response when the mutation is executed again: 937 938 ```json 939 { 940 "data": { 941 "code": "Success", 942 "message": "Done", 943 "uids": {} 944 }, 945 "extensions": {...} 946 } 947 ``` 948 949 We can achieve the same result using `json` dataset as follows: 950 951 ```sh 952 curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d ' 953 { 954 "query": "{ v as var(func: eq(email, \"user@company1.io\")) }", 955 "set": { 956 "uid": "uid(v)", 957 "name": "first last", 958 "email": "user@company1.io" 959 } 960 } 961 ' | jq 962 ``` 963 964 Now, we want to add the `age` information for the same user having the same email 965 `user@company1.io`. We can use the upsert block to do the same as follows: 966 967 ```sh 968 curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true -d $' 969 upsert { 970 query { 971 v as var(func: eq(email, "user@company1.io")) 972 } 973 974 mutation { 975 set { 976 uid(v) <age> "28" . 977 } 978 } 979 } 980 ' | jq 981 ``` 982 983 Result: 984 985 ```json 986 { 987 "data": { 988 "code": "Success", 989 "message": "Done", 990 "uids": {} 991 }, 992 "extensions": {...} 993 } 994 ``` 995 996 Here, the query block queries for a user with `email` as `user@company1.io`. It stores 997 the `uid` of the user in variable `v`. The mutation block then updates the `age` of the 998 user by extracting the uid from the variable `v` using `uid` function. 999 1000 We can achieve the same result using `json` dataset as follows: 1001 1002 ```sh 1003 curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d ' 1004 { 1005 "query": "{ v as var(func: eq(email, \"user@company1.io\")) }", 1006 "set":{ 1007 "uid": "uid(v)", 1008 "age": "28" 1009 } 1010 } 1011 ' | jq 1012 ``` 1013 1014 If we want to execute the mutation only when the user exists, we could use 1015 [Conditional Upsert]({{< relref "#conditional-upsert" >}}). 1016 1017 ### Bulk Delete Example 1018 1019 Let's say we want to delete all the users of `company1` from the database. This can be 1020 achieved in just one query using the upsert block: 1021 1022 ```sh 1023 curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true -d $' 1024 upsert { 1025 query { 1026 v as var(func: regexp(email, /.*@company1.io$/)) 1027 } 1028 1029 mutation { 1030 delete { 1031 uid(v) <name> * . 1032 uid(v) <email> * . 1033 uid(v) <age> * . 1034 } 1035 } 1036 } 1037 ' | jq 1038 ``` 1039 1040 Result: 1041 1042 ```json 1043 { 1044 "data": { 1045 "code": "Success", 1046 "message": "Done", 1047 "uids": {} 1048 }, 1049 "extensions": {...} 1050 } 1051 ``` 1052 1053 We can achieve the same result using `json` dataset as follows: 1054 1055 ```sh 1056 curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d $'{ 1057 "query": "{ v as var(func: regexp(email, /.*@company1.io$/)) }", 1058 "delete": { 1059 "uid": "uid(v)", 1060 "name": null, 1061 "email": null, 1062 "age": null 1063 } 1064 } 1065 ' | jq 1066 ``` 1067 1068 ## Conditional Upsert 1069 1070 The upsert block also allows specifying a conditional mutation block using an `@if` 1071 directive. The mutation is executed only when the specified condition is true. If the 1072 condition is false, the mutation is silently ignored. The general structure of 1073 Conditional Upsert looks like as follows: 1074 1075 ``` 1076 upsert { 1077 query <query block> 1078 [fragment <fragment block>] 1079 mutation @if(<condition>) <mutation block> 1080 } 1081 ``` 1082 1083 The `@if` directive accepts a condition on variables defined in the query block and can be 1084 connected using `AND`, `OR` and `NOT`. 1085 1086 ### Example 1087 1088 Let's say in our previous example, we know the `company1` has less than 100 employees. 1089 For safety, we want the mutation to execute only when the variable `v` stores less than 1090 100 but greater than 50 UIDs in it. This can be achieved as follows: 1091 1092 ```sh 1093 curl -H "Content-Type: application/rdf" -X POST localhost:8080/mutate?commitNow=true -d $' 1094 upsert { 1095 query { 1096 v as var(func: regexp(email, /.*@company1.io$/)) 1097 } 1098 1099 mutation @if(lt(len(v), 100) AND gt(len(v), 50)) { 1100 delete { 1101 uid(v) <name> * . 1102 uid(v) <email> * . 1103 uid(v) <age> * . 1104 } 1105 } 1106 } 1107 ' | jq 1108 ``` 1109 1110 We can achieve the same result using `json` dataset as follows: 1111 1112 ```sh 1113 curl -H "Content-Type: application/json" -X POST localhost:8080/mutate?commitNow=true -d '{ 1114 "query": "{ v as var(func: regexp(email, /.*@company1.io$/)) }", 1115 "cond": "@if(lt(len(v), 100) AND gt(len(v), 50))", 1116 "delete": { 1117 "uid": "uid(v)", 1118 "name": null, 1119 "email": null, 1120 "age": null 1121 } 1122 }' | jq 1123 ```