Gremlin, join vertices of same type and add edge when the properties empNo and mgrno matches - graph

I have vertices with properties like
vertex("empNo","age","Date","mgrNo")
a(101,20,'dd-mm-yy',0)
b(102,22,'dd-mm-yy',101)
Since mgrNo of b matches with empNo of a ie, a is the manager of b.
I have to add an edge between a and b.
Please tell me how to do this in gremlin .

I assume that you want to iterate all vertices. You could do it with a sideEffect pretty easily:
g.V.has("mgrNo",neq,0).sideEffect{
g.V.has("empNo",it.mgrNo).next().addEdge("manages",it)
}
Note that if you are using a graph that supports transactions you will need to commit() your changes to persist them.

Related

Generalized subqueries in Cypher 9

I have a graph in Neo4j, where all nodes and edges have a property p. With a cypher query as follows, I get a subgraph of the whole graph that fulfills several conditions on p for vertices and edges in general.
Q1
MATCH (n)
WHERE n.p ... // some conditions for nodes
OPTIONAL MATCH (n)-[r]-()
WHERE r.p ... // some conditions for relationships
RETURN n,r
Now I want to execute a second query Q2 on the resulting subgraph of the first query Q1. For example
Q2
MATCH (a:Person)-[:knows*5]-(b:Person)-[s:studiedAt]-(u:University),
(b)-[:owns]-(i:Business)
WHERE i.city = "Boston"
RETURN DISTINCT a.name, i.name, u.name
I do not want to apply the general conditions of Q1 for each vertex and edge in Q2. That complicates the query, loses the generalization, and needs path variables for variable paths like [:knows*5].
Is there a smarter way to execute a query Q2 on the result of a query Q1? Or is this impossible in Cypher because of its missing composability and the fact, that the result is always a table and never a graph?
It's not present directly in Cypher as far as I know, but if you are using Neo4j Enterprise, then you can use Neo4j Graph Data Science Library, to create named subgraphs, and then you can query those subgraphs. The disadvantage that comes with this approach is your subgraph won't be updated as the original graph gets updated. Please go through the following documentation, on how to create a subgraph:
Projecting a subgraph
Querying your subgraph

UPSERT an edge with properties with Gremlin

I'm trying to upsert an edge (insert if it does not exist but update if it does) with properties in Gremlin via a single query.
I have this which adds a manages edge with a duration property between two vertices with id of Amy and John.
g.E().where(outV().has('id','Amy')).where(inV().has('id','John')).fold().coalesce(unfold(),g.V('Amy').as('a').V('John').addE('manages').from('a').property('duration','1year')).
The query does do an upsert, but if I change the value of the duration property, remove the duration property, or add other properties, the property changes are not reflected on the edge.
I want to be able to change the value of the duration property without adding a new edge or having to remove the old one.
I'm fairly new to Gremlin so please share any advice which may help.
I'm not sure it matters but the underlying DB is an Azure Cosmos DB.
To always have the property change apply whether the edge exists or is created, you just need to move the property step to after the coalesce:
g.E().
where(outV().has('id', 'Amy')).
where(inV().has('id', 'John')).
fold().
coalesce(
unfold(),
g.V('Amy').as('a').
V('John').
addE('manages').from('a')).
property('duration', '1year')
However, that said, there are a few observations that can be made about the query. Starting with g.E() is likely to be inefficient and using g.V() mid traversal should be avoided, and where necessary just V() used.
If 'John" and 'Amy' are unique ID's you should take advantage of that along these lines:
g.V('Amy').
outE().where(inV().hasId('John')).
fold().
coalesce(
unfold(),
addE('manages').from(V('Amy')).to(V('John'))).
property('duration', '1year')
Two additions to Kevin's answer:
I think you need to specify the edge label in outE, otherwise the unfold may return other relationships present between the two vertices, and these will be updated with the property, rather than triggering the addE of the new edge. Specifying the edge label should ensure the length of the folded array is 0 in the case of INSERT and 1 in the case of UPDATE.
For Cosmos DB Gremlin API, use the anonymous class __ when not using g
g.V('Amy').
outE('manages').where(inV().hasId('John')).
fold().
coalesce(
unfold(),
__.addE('manages').from(__.V('Amy')).to(__.V('John'))).
property('duration', '1year')
More detailed example here.

How to filter by property in Gremlin (if exist)?

I am new Gremlin and having trouble with filtering by property.
A -> B
Assume A and B are vertices and has edge between them with properties Created_on and deleted_on.
deleted_on property will be added only at the time of deletion.
How list by the edge property?
g.V(id).outE('Label').has('deleted_on', lt(timestamp.now())).outV().elementMap()
The above query returns empty, because the deleted_on property is not added to the edge yet.
How to handle this?
I'm not completely sure but I think you are looking to find all connections where the deleted_on property is less than now or it does not exist. If that is the case then you can use the or() and hasNot() steps in Gremlin to accomplish this similar to the query below.
g.V(id).
outE('Label').
has('deleted_on', lt(timestamp.now())).
or().
hasNot('deleted_on').
outV().
elementMap()

Create Vertex only if "from" and "to" vertex exists

I want to create 1000+ Edges in a single query.
Currently, I am using the AWS Neptune database and gremlin.net for creating it.
The issue I am facing is related to the speed. It took huge time because of HTTP requests.
So I am planning to combine all of my queries in a string and executing in a single shot.
_g.AddE("allow").From(_g.V().HasLabel('person').Has('name', 'name1')).To(_g.V().HasLabel('phone').Where(__.Out().Has('sensor', 'nfc'))).Next();
There are chances that the "To" (target) Vertex may not be available in the database. When it is the case this query fails as well. So I had to apply a check if that vertex exists before executing this query using hasNext().
So as of now its working fine, but when I am thinking of combining all 1000+ edge creation at once, is it possible to write a query which doesn't break if "To" (target) Vertex not found?
You should look at using the Element Existence pattern for each vertex as shown in the TinkerPop Recipes.
In your example you would replace this section of your query:
_g.V().HasLabel('person').Has('name', 'name1')
with something like this (I don't have a .NET environment to test the syntax):
__.V().Has('person', 'name', 'name1').Fold().
coalesce(__.Unfold(), __.AddV('person').Property('name', 'name1')
This will act as an Upsert and either return the existing vertex or add a new one with the name property. This same pattern can then be used on your To step to ensure that it exists before the edge is created as well.

Gremlin query: Find all the related vertices till end which match with edge properties

I need to start with one vertex and find all the related vertices till end. Criteria is to match any one of the edge properties(attributes) in the edge inV vertex. If edge attribute ‘value’ doesn’t match inV vertex ‘attribute’ name I should skip the vertex. Attribute value of edge is propagated as Attribute name in the inV vertex
Am using below query, however this gives me json output of parent node, next node and edges between. With the output am writing logic to pick only next attributes which match with the edge attributes. If the matching of attributes can be done with gremlin query, that would be great
var graphQuery = "g.V().has('sPath', '/Assisted/CSurvey/CSurvey.ss').as('ParentStream').outE.inV().as('Edges').map(select('Edges').inV().fold()).as ('NextStream').select('ParentStream', 'NextStream','Edges')";
In below/attached image. I need to get vertex1 and vertex2 and skip vertex3 as there are no attributes matching with edge
image link
Use graph traversal and filter
Example in Scala:
graph.traversal().V().has().bothE('sPath').filter{it:Edge =>
(it.property('sPath').value() == '/Assisted/CSurvey/CSurvey.ss')}.toList()
Hope this helps

Resources