Creating relationships taking too long in Neo4j using Neo4php - neo4j

I have been trying to create nodes and relations ships for our new module with neo4jphp [https://github.com/jadell/neo4jphp/wiki].
I am using cypher queries for the same.
Creating nodes with below query:
$queryNodes = "CREATE (n:User { props } ) ";
$query = new Everyman\Neo4j\Cypher\Query($client, $queryNodes, array('props' => $arrNodeProperties));
$result = $query->getResultSet();
Creating relationships with below query:
$queryRelations = "
MATCH (authUser: User { userid: 0001 }),(friend)
WHERE friend.userid IN ['" . implode("','",$relations) . "']
CREATE UNIQUE (authUser)-[r:KNOWS { connection: 'user_friend' }]->(friend)";
So far node creation works gr8.
But when i try to create Unique relationships for the nodes, it takes too long....
Note:
There is unique constraint userid for label User, hence node with label user is indexed by Neo4j on property userid.
CREATE CONSTRAINT ON (user:User) ASSERT user.userid IS UNIQUE
Questions:
Is there any other way we can achieve creating unique relationships.
Can i use index on relationships?? If Yes how can I achieve the same.

You might try use use MERGE instead of CREATE UNIQUE. Additionally use a Cypher parameter for the fried's list instead of concatenation on client side, see http://docs.neo4j.org/chunked/stable/cypher-parameters.html

Finally I worked it out with few changes...
Thanks #MichaelHunger for the help.
So here is how i did it...
Creating Unique Nodes using MERGE, FOREACH, ON CREATE SET and params:
$queryNodes = "
FOREACH (nodeData IN {nodeProperties}|
MERGE (n:User { userid: nodeData.userid })
ON CREATE SET
n.login = nodeData.login,
n.userid = nodeData.userid,
n.username = nodeData.username,
n.name = nodeData.name,
n.gender = nodeData.gender,
n.profile_pic = nodeData.profile_pic,
n.create_date = timestamp()
ON MATCH SET
n.update_date = timestamp()
)
";
$query = new Everyman\Neo4j\Cypher\Query($client, $queryNodes, array('nodeProperties' => $arrNodeProperties));
$result = $query->getResultSet();
Creating Unique Relationships with below query:
$queryRelations = "
MATCH (authUser: User { userid: {authUserid} }), (friend:User)
WHERE friend.userid IN {friendUserIds}
CREATE UNIQUE (authUser)-[r:KNOWS { connection: 'user_friend' }]->(friend)
";
$query = new Everyman\Neo4j\Cypher\Query($client, $queryRelations, array('friendUserIds' => $arrFriendUserId, 'authUserid' => $authUserid));
$result = $query->getResultSet();
Please comment if we can improve the same even further.

Related

How to query with two conditions in Neo4j

I am new with Neo4j and I am stucked trying to get a query with two conditions, where I want to get all the "Autors" related to "Pixar" and "Fox". So far I have tried the following two ways:
MATCH (a:Autor)- [:AUTOR_DE]-> (t:Título) -[:PRODUCIDO_POR] ->( p:Productora {Nombre: "Pixar"}),
and
MATCH (a:Autor)- [:AUTOR_DE]-> (t:Título) -[:PRODUCIDO_POR] ->( p:Productora {Nombre: "Fox"}),
return a,p
and
MATCH (a:Autor)- [:AUTOR_DE]-> (t:Título) -[:PRODUCIDO_POR] ->( p:Productora)
WHERE ( (p:Productora) = "Fox" OR (p:Productora) = "Pixar")
return a,p
Thanks in advance
Assuming that a Productora node stores its name in a name property, and that every Productora node has a unique name, this should work:
MATCH (a:Autor)-[:AUTOR_DE]->(:Título)-[:PRODUCIDO_POR]->(p:Productora)
WHERE p.name = "Fox" OR p.name = "Pixar"
WITH a, COLLECT(DISTINCT p) AS ps
WHERE SIZE(ps) = 2
return a, ps
And this should also work:
MATCH (fox:Productora), (pixar:Productora), (a:Autor)
WHERE fox.name = "Fox" AND pixar.name = "Pixar" AND
(a)-[:AUTOR_DE]->(:Título)-[:PRODUCIDO_POR]->(fox) AND
(a)-[:AUTOR_DE]->(:Título)-[:PRODUCIDO_POR]->(pixar)
return a, fox, pixar

Cypher query and multi-pass references

I have the following Cypher query that looks for the Permission for User via Role:
MATCH (p:Permission)<-[:CONTAINS]-(r:Role)<-[:HAS]-(u:User)
WHERE u.id = {userId} AND p.type = {permissionType} AND p.code = {permissionCode}
RETURN p
This query works fine.
Also, the User can have a direct relationship with the Permission:
(p:Permission)<-[:HAS]-(u:User)
How to extend the original query in order to also look for the Permission that is directly associated with the User?
You can try this :
MATCH (p:Permission)<-[:HAS|:CONTAINS*1..2]-(u:User)
WHERE u.id = {userId} AND p.type = {permissionType} AND p.code = {permissionCode}
RETURN p
Cheers

Get relationship type in a php variable of neo4j

What I want is that: I have two nodes with id 1 and id 2. It has a relationship type (id:1)-[r:Knows]->(id:2). My query is working fine in Neo4j as localhost but I am not able to store that relationship type in a PHP variable to use further. I am using graphware.
Note: $id = 1 and $s_id = 2.
$queryString = "MATCH (a:signup{iid:'$id'})-[r]->(b:signup{iid:'$s_id'}) return type(r) ";
$query = new Everyman\Neo4j\Cypher\Query($client, $queryString);
$result = $query->getResultSet();
if($result == 'Knows')
{
$s_relation = $result;
}
else
{
$s_relation = 'empty';
}
It returns the else part as EMPTY.
Thank you.
Well, I found a solution for this.

neo4j sum up values

I'm trying to get Total(Sum) of a property of "df" object.I have attached screen shot of sample database I'm using
I tried to get the graph using following query
MATCH P= (n:Org)-[:O_CH*0..]->()-[:LEAF*0..]->()-[:CH*0..]->()-[:FOR*0..]->() RETURN P
To create objects
create(n:Org{name:'Root',id:1})
create(n:Org{name:'L1.1',id:2,parent:1})
create(n:Org{name:'L1.2',id:3,parent:1})
create(n:Org{name:'L1.3',id:4,parent:1})
create(n:Org{name:'L2.1',id:5,parent:3})
create(n:Org{name:'L2.2',id:6,parent:4})
create(n:Op{name:'CH1',id:7,orgId:5})
create(n:Op{name:'CH2',id:8,orgId:5 ,parent:'CH1'})
create(n:Proj{name:'P1',id:9,opp:'CH2'})
create(n:Proj{name:'P2',id:10,opp:'CH1'})
create(n:R{name:'R1',id:200,orgId:2 })
create (n:df{id:100,map:8,forecast:toFloat(10)})
create (n:df{id:101,map:7,forecast:toFloat(10)})
create (n:df{id:102,map:9,forecast:toFloat(10)})
create (n:df{id:103,map:10,forecast:toFloat(10)})
create (n:df{id:104,map:200,forecast:toFloat(10)})
To Crate relationships
MATCH (c:Org),(p:Org) WHERE c.parent = p.id create (p)-[:O_CH]->(c)
MATCH (c:Op),(p:Op) WHERE c.parent = p.name create (p)-[:CH]->(c)
MATCH (c:Op),(p:Org) WHERE c.orgId = p.id create (p)-[:LEAF]->(c)
MATCH (c:Proj),(p:Op) WHERE c.opp = p.name create (p)-[:CH]->(c)
MATCH (c:R),(p:Org) WHERE c.orgId = p.id create (p)-[:LEAF]->(c)
MATCH (c:df),(p:) WHERE c.map = p.id create (p)-[:FOR]->(c)
I'm expecting 60 as total where I get 260 as total. Please let me know where I'm wrong . Need your help to figure out.
I'm trying to get Total(Sum) of a property of "df" object.
I believe you needs a simple query that match all nodes with label :df and return the sum of node.forecast. Try it:
// Match all nodes with :df label
MATCH(n:df)
// Return the sum of the property 'forecast' of each matched node
RETURN sum(n.forecast)
From comments:
Thank you Bruno.But the thing i need to get the aggregated value as a
example if i select L2.1 , i need to get the sum of df objects which
are under that node
This should work:
MATCH({name:'L2.1'})-[*]->(n)
RETURN SUM(n.forecast)

How to add unique data to a neo4j graph database

I am adding iteratively data to my neo4j database but I am stuck with how to overwrite or update existing data and to check whether the data does not already exist in there.
Basically I have a set of movies with their corresponding id's, e.g.:
[
{id: 'gameofthrones', genre: 'fantasy', release: '2017'},
{id: 'inception', genre: 'scifi', release: '2010'},
...
]
I can add the movies as follows:
CREATE
(m1:Movie {id: 'gameofthrones', genre: 'fantasy', release: '2017'}),
(m2:Movie {id: 'inception', genre: 'scifi', release: '2010'})
However, when I run the script two times, then it creates 4 nodes instead of keeping it at two nodes.
So my question is, how can I make sure that it checks whether the node id is already present, and if so overwrite it instead of creating a new node?
I tried (but only the properties get added)
// data
attributes['id'] = 'gameofthrones';
attributes['genre'] = 'fantasy';
...
// query
MERGE ( s:Movie {attributes}.id)
ON CREATE SET ( s:Movie {attributes} )
which I call in NodeJS as follows:
executeQuery(queryStr, {"attributes": attributes})
// cypher (nodejs)
function executeQuery(queryStr, params) {
var qq = Q.defer();
db.cypher({
query: queryStr,
params: params,
}, function (error, results) {
if (error) {
qq.reject(error);
} else {
if (results.length != 0) {
qq.resolve(true);
} else {
qq.resolve(false);
}
};
});
return qq.promise;
};
you must change your query to this
MERGE ( s:Movie {attributes}.id)
ON CREATE SET s += {attributes}
ON MATCH SET s += {attributes} // optional
this should work, but you should use apoc.map.clean() so you do not set the id twice, which can cause some problems.
MERGE ( s:Movie {attributes}.id)
ON CREATE SET s += apoc.map.clean({attributes},['id'],[])
You can achieve this with MERGE clause as follows
MERGE (m1:Movie {id: 'gameofthrones'})
ON CREATE SET m1.genre = 'fantasy', m1.release = '2017'
MERGE (m2:Movie {id: 'inception'})
ON CREATE SET m2.genre: 'scifi', m2.release = '2010'
Ideally you want to create queries with parameters instead of literal strings. You can achieve this if you user apoc.load.json
with "file:///home/sample.json" as url // can be also http://url/sample.json
CALL apoc.load.json(url) yield value
UNWIND value as item
MERGE (m1:Movie {id: item.id})
ON CREATE SET m1.genre = item.genre, m1.release = item.release
example for dynamic properties with apoc functions:
with "file:///home/sample.json" as url // can be also http://url/sample.json
CALL apoc.load.json(url) yield value
UNWIND value as item
MERGE (m1:Movie {id: item.id})
ON CREATE SET m1 += apoc.map.clean(item,['id'],[])
or if you do not have apoc plugin:
with "file:///home/sample.json" as url // can be also http://url/sample.json
CALL apoc.load.json(url) yield value
UNWIND value as item
MERGE (m1:Movie {id: item.id})
ON CREATE SET m1 += item
note that id will first be merged and later updated with ON CREATE SET and you want to avoid writing a single property twice, using apoc and above query we can achieve that

Resources