Context: this question
The following commands can be exectuted from within the Data Explorer interface of an Azure Cosmos DB Gremlin API database resource, or from other gremlin consoles such as a local TinkerPop installation.
This can be in an empty graph, like that created when adding a graph in Azure Cosmos DB Gremlin API or added to an exsisting graph, like for example the 'modern' sample graph from the Tinkerpop Getting Started documentation.
g.addV("person").property("pk","pk").property("id","a").property("name","Alice")
g.addV("person").property("pk","pk").property("id","c").property("name","Charlie")
💡 Note that in the following, we show selecting a Vertex by property (
V().has("property","value")
). This assumes that the Vertex ID is not known by the application. In the local Tinkerpop Gremlin console, the ID is an autogenerated integer, and so this approach is compatible. In Cosmos DB Gremlin API, the ID is theid
property, which can be set as a string as in the example above. This could simplify node selection toV('<id>')
.
View existing edges of type reports_to
:
g.V().has("name","Charlie").outE("reports_to").where(inV().has("name","Alice"))
💡 Note, Cosmos DB adds a
label
property to edges, meaning the same filtering can be achieved by using a genericoutE()
in the statement, and adding a property filter as below. This does not work in a local TinkerPop console.
g.V().has("name","Charlie").outE().where(inV().has("name","Alice")).
has("label","reports_to")
-> none
Add a new edge if it does not exist (Upsert)
g.V().has("name","Charlie").outE("reports_to").where(inV().has("name","Alice")).
fold().
coalesce(
unfold(),
__.addE("reports_to").from(__.V().has("name","Charlie")).to(__.V().has("name","Alice"))).
property("duration","1y")
[
{
"id": "44011121-037c-4900-b857-cfbb1dc6c23a",
"label": "reports_to",
"type": "edge",
"inVLabel": "person",
"outVLabel": "person",
"inV": "a",
"outV": "c",
"properties": {
"duration": "1y"
}
}
]
Update the same edge (Upsert)
g.V().has("name","Charlie").outE("reports_to").where(inV().has("name","Alice")).
fold().
coalesce(
unfold(),
__.addE("reports_to").from(__.V().has("name","Charlie")).to(__.V().has("name","Alice"))).
property("duration","4y")
[
{
"id": "44011121-037c-4900-b857-cfbb1dc6c23a",
"label": "reports_to",
"type": "edge",
"inVLabel": "person",
"outVLabel": "person",
"inV": "a",
"outV": "c",
"properties": {
"duration": "4y"
}
}
]
Remove the relationship type constraint: view relationships:
g.V().has("name","Charlie").outE().where(inV().has("name","Alice"))
This may return multiple relationships between the two nodes, if the manages
relationship was created previously:
[
{
"id": "0d6531cf-ec76-4be3-b568-b1fc0b758ab2",
"label": "manages",
"type": "edge",
"inVLabel": "person",
"outVLabel": "person",
"inV": "a",
"outV": "c",
"properties": {
"duration": "2y"
}
},
{
"id": "44011121-037c-4900-b857-cfbb1dc6c23a",
"label": "reports_to",
"type": "edge",
"inVLabel": "person",
"outVLabel": "person",
"inV": "a",
"outV": "c",
"properties": {
"duration": "4y"
}
}
]
g.V().has("name","Charlie").outE().where(inV().has("name","Alice")).
fold().
coalesce(
unfold(),
__.addE("manages").from(__.V().has("name","Charlie")).to(__.V().has("name","Alice"))).
property("duration","3y")
[
{
"id": "0d6531cf-ec76-4be3-b568-b1fc0b758ab2",
"label": "manages",
"type": "edge",
"inVLabel": "person",
"outVLabel": "person",
"inV": "a",
"outV": "c",
"properties": {
"duration": "3y"
}
},
{
"id": "44011121-037c-4900-b857-cfbb1dc6c23a",
"label": "reports_to",
"type": "edge",
"inVLabel": "person",
"outVLabel": "person",
"inV": "a",
"outV": "c",
"properties": {
"duration": "3y"
}
}
]
follows
) and update the property in one go, as the other relationships would trigger the unfold
rather than the new relationship creation within the coalesce
statement. Again, the existing relationships are updated and the addE('follows') is never hit.
g.V().has("name","Charlie").outE().where(inV().has("name","Alice")).
fold().
coalesce(
unfold(),
__.addE("follows").from(__.V().has("name","Charlie")).to(__.V().has("name","Alice"))).
property("duration","6y")
[
{
"id": "0d6531cf-ec76-4be3-b568-b1fc0b758ab2",
"label": "manages",
"type": "edge",
"inVLabel": "person",
"outVLabel": "person",
"inV": "a",
"outV": "c",
"properties": {
"duration": "6y"
}
},
{
"id": "44011121-037c-4900-b857-cfbb1dc6c23a",
"label": "reports_to",
"type": "edge",
"inVLabel": "person",
"outVLabel": "person",
"inV": "a",
"outV": "c",
"properties": {
"duration": "6y"
}
}
]
✔️ instead, to add a new 'follows' relationship, ensure the initial fold is filtered to that specific relationship, as per the Upsert example at the start of this post:
g.V().has("name","Charlie").outE("follows").where(inV().has("name","Alice")).
fold().
coalesce(
unfold(),
__.addE("follows").from(__.V().has("name","Charlie")).to(__.V().has("name","Alice"))).
property("duration","6y")
[
{
"id": "d168a86c-6d9e-4373-a4e6-98211fb80958",
"label": "follows",
"type": "edge",
"inVLabel": "person",
"outVLabel": "person",
"inV": "a",
"outV": "c",
"properties": {
"duration": "6y"
}
}
]