Upsert data to graph
This endpoint upserts vertices and/or edges into a graph. To upsert means that if a vertex or edge does not exist, it is inserted, and if it does exist, it is updated.
Upserting vertices or edges require the user to have sufficient privileges. See Access Control Model in TigerGraph.
Parameters
The following table describes the URL parameters for the endpoint.
Name | Required | Description | ||
---|---|---|---|---|
|
No |
The value of this parameter can either be
Default value is |
||
|
No |
If |
||
|
No |
If |
||
|
No |
If |
||
|
No |
If the value is This parameter does not affect vertices.
Default value is |
||
|
No |
If the value is This parameter does not affect vertices. For non-directed edges, the behavior of this parameter is identical to This parameter is mutually exclusive with the general |
||
|
No |
If the value is This parameter does not affect vertices. For non-directed edges, the behavior of this parameter is identical to This parameter is mutually exclusive with the general |
Response
The response is the number of vertices and edges that were accepted. Additionally, if new_vertex_only
is true, the response will include two more fields:
-
skipped_vertices
: the number of vertices in the input data which already existed in the graph -
vertices_already_exist
: the id and type of the input vertices which were skipped
If vertex_must_exist
is true, the response will include two more fields:
-
skipped_edges
: the number of edges in the input data rejected because of missing endpoint vertices -
miss_vertices
: the id and type of the endpoint vertices which were missing
The example file add_id6.json
(shown in the Request Body section) upserts one User
vertex with id = "id6"
, one Liked
edge, and one Liked_By
edge. The Liked
edge is from "id1
" to "id6"
; the Liked_By
_edge is from "id6"
to _"id1"
.
Request body
The payload data should be in JSON according to the schema shown below:
{
"vertices": {
"<vertex_type>": {
"<vertex_id>": {
"<attribute>": {
"value": <value>,
"op": <opcode>
}
}
}
},
"edges": {
"<source_vertex_type>": {
"<source_vertex_id>": {
"<edge_type>": {
"<target_vertex_type>": {
"<target_vertex_id>": {
"<attribute>": {
"value": <value>,
"op": <opcode>
}
}
}
}
}
}
}
}
The fields in angle brackets (<>
) are placeholder names or values, to be replaced with actual values.
The keys in angle parentheses, such as <vertex_type>
, can be repeated to form a list of items.
The keys which are not in angle brackets are exact texts that must be used as they are.
The nested hierarchy means that vertices are grouped by type.
Edges, on the other hand, are first grouped by source vertex type, then vertex ID, then edge type.
Examples
The first example below shows two User
vertices having an attribute called age
:
{
"vertices": {
"User": {
"id6": {
"age": {
"value": 30
}
},
"id1": {
"age": {
"value": 22
}
}
}
}
}
The second example starts with one User
vertex.
Since id6
contains no attributes, it will remain the same it if already exists.
If it doesn’t yet exist, the request will create a vertex with ID id6
with default attribute values.
Then two edges are created: a Liked
edge from id1
to id6
, and then a Liked_By
edge from id6
to id1
.
{
"vertices": {
"User": {
"id6": {
}
}
},
"edges": {
"User":{
"id1": {
"Liked": {
"User": {
"id6" : {
"weight" : {
"value": 5.0
}
}
}
}
},
"id6": {
"Liked_By": {
"User": {
"id1" : {
"weight" : {
"value": 1.0
}
}
}
}
}
}
}
}
Follow the instructions in the Introduction section to format advanced data types.
For example, the following payload is used to upsert two User
vertices with an attribute coordinates
of type LIST
and an attribute measurements
of type MAP
:
{
"vertices": {
"User": {
"id4": {
"coordinates": {
"value": [51.3345, -7.2233]
},
"measurements": {
"value": {
"keyList": ["chest", "waist", "hip"]
"valueList": [35, 30, 35]
}
}
},
"id5": {
"coordinates": {
"value": [31.3245, -17.3292]
},
"measurements": {
"value": {
"keyList": ["chest", "waist", "hip"]
"valueList": [39, 35, 41]
}
}
}
}
}
}
Operation codes
Each attribute value may be accompanied by an operation (op) code, which provides very sophisticated schemes for data update or insertion:
Type | op | Meaning |
---|---|---|
1 |
|
If the vertex/edge does not exist, use the payload value to initialize the attribute; but if the vertex/edge already exists, do not change this attribute. |
2 |
|
Add the payload value to the existing value. |
3 |
|
Update to the logical AND of the payload value and the existing value. |
4 |
|
Update to the logical OR of the payload value and the existing value. |
5 |
|
Update to the higher value between the payload value and the existing value. |
6 |
|
Update to the lower value between the payload value and the existing value. |
If an attribute is not given in the payload, the attribute stays unchanged if the vertex/edge already exists, or if the vertex/edge does not exist, a new vertex/edge is created and assigned the default value for that data type. The default value is 0 for int/uint
, 0.0 for float/double
, and ""
(empty string) for string.
Upserting vertices with composite keys
If your vertex has composite keys, separate the attributes that make up the composite key with a comma (,
) in the same order as they are defined in the schema.
For example, suppose we have the following vertex definition:
CREATE VERTEX Composite_Person(id UINT, name STRING, age UINT, primary key (name, id))
CREATE VERTEX Composite_Movie (id UINT, title STRING, country STRING, year UINT, PRIMARY KEY (title,year,id))
CREATE DIRECTED EDGE Composite_Roles (from Composite_Person,to Composite_Movie, role STRING)
CREATE GRAPH Person_Movie(Composite_Person, Composite_Movie, Composite_Roles)
The following requests upserts two vertices with the defined composite key, as well as an edge of the type Composite_Roles
between Bob, 123
and Harry Potter, 1990, 1337
:
curl -X POST "localhost:9000/graph/Person_Movie" -d '
{
"vertices": {
"Composite_Person":{
"Bob,123":{
"name":{"value":"Bob"},
"id":{"value":123},
"age":{"value":25}
},
"Tom,456":{
"name":{"value":"Tom"},
"id":{"value":456},
"age":{"value":47}
}
}
},
"edges":{
"Composite_Person":{
"Bob,123":{
"Composite_Roles":{
"Composite_Movie":{
"Harry Potter,1990,1337":{
"role":{
"value":"Wizard"
}
}
}
}
}
}
}
}
'
Upserting edges with discriminators
Some edge types are defined with discriminators, which allow multiple instances of the same edge type between two vertices.
To upsert an edge that was defined with a discriminator, insert them as a regular edge. However, the following rules apply:
-
You cannot leave off discriminator attributes when inserting an edge whose type was defined with discriminator attributes.
-
If you are updating an existing edge, you cannot update the attributes that are defined as part of the edge type discriminator.
For example, if you have the following edge type definition:
CREATE DIRECTED EDGE Study_At(From Person, To University, DISCRIMINATOR(class_year INT, class_month INT), major STRING))
When inserting an edge of type Study_AT
, you cannot omit the class_year
attribute or the class_month
attribute.
You cannot update these two attributes either.
Valid data types
The RESTPP server validates the request before updating the values. The following schema violations will cause the entire request to fail and no change will be made to a graph:
-
For vertex upsert
-
Invalid vertex type
-
Invalid attribute data type
-
-
For edge upsert:
-
Invalid source vertex type
-
Invalid edge type
-
Invalid target vertex type
-
Invalid attribute data type.
-
If an invalid attribute name is given, it is ignored.
Example
The following example submits an upsert request by using the payload data stored in add_id6.json
.
curl -X POST --data-binary @add_id6.json "http://localhost:9000/graph"
{"accepted_vertices":1,"accepted_edges":2}
If we set the value of vertex_must_exist
parameter to true
, the endpoint will only insert edges whose endpoint vertices both exist. This includes the vertices being inserted in the same request.
Therefore, inserting the content of add_id6.json
to an empty graph would cause the edges to be rejected:
curl -X POST --data-binary @add_id6.json "http://localhost:9000/graph?vertex_must_exist=true"
{
"version": {
"edition": "enterprise",
"api": "v2",
"schema": 0
},
"error": false,
"message": "",
"results": [
{
"accepted_vertices": 1,
"accepted_edges": 0,
"skipped_edges": 2,
"edge_vertices_not_exist": [
{
"v_type": "User",
"v_id": "id1"
}
]
}
],
"code": "REST-0003"
}
Atomic upsert transaction
By default, the POST /graph/{graph_name}
endpoint is not atomic. If something goes wrong during the process of the request, the request data can be partially consumed by the database.
You can append a request header gsql-atomic-level
to the request to set the request’s atomicity level.
The header parameter accepts the following values:
-
atomic
: The request is an atomic transaction. An atomic transaction means that updates to the database contained in the request are all-or-nothing: either all changes are successful, or none is successful. -
nonatomic
: The request is not atomic. This is the default behavior of the endpoint.
For example, suppose we have the following request to upsert two vertices:
curl --data-binary @vertices.json http://localhost:9000/graph/social
Content of vertices.json
is:
{
"vertices": {
"person": {
"Velma": {
"age": {
"value": 30
}
},
"Kelly": {
"age": {
"value": 22
}
}
}
}
}
With the request above, if the vertex Kelly
fails to be upserted due to a machine failure, it is still possible that the vertex Velma
is upserted to the database.
If you add the gsql-atomic-level
header to the request URL and set its value to atomic
, the request becomes atomic and if any part of the request body fails to be upserted, nothing will be upserted:
# This is an atomic request
curl -X POST -H 'gsql-atomic-level:atomic' --data-binary @vertices.json http://localhost:9000/graph/social