I am using Neo4J v2.1.5 and creating a server plugin.
How to create a unique node i.e. guarantee uniqueness of a property?
Is there a hook where in the plugin lifecycle, constraints and indexes can be created?
Returning a node returns the complete database. How can I return just a node or a pojo list as JSON? Are there any working examples or explanation of Representation available?
I am using Java API and not Cypher.
How to create a unique node i.e. guarantee uniqueness of a property?
You can create a unique constraint on a (label, property) pair which will ensure the uniqueness of that property.
e.g.
CREATE UNIQUE CONSTRAINT ON :Person(name)
Would ensure you can't have two people nodes with the same name. If you want to do that from the Java API you'd do something like this:
try ( Transaction tx = graphdb.beginTx() )
{
graphdb.schema()
.constraintFor( DynamicLabel.label( "Person" ) )
.assertPropertyIsUnique( "name" )
.create();
tx.success();
}
Is there a hook where in the plugin lifecycle, constraints and indexes can be created?
You can do that in a transaction but IIRC you can only create one index/constraint per transaction.
Returning a node returns the complete database. How can I return just a node or a pojo list? Are there
any working examples or explanation of Representation available?
Do you mean from cypher? A simple query which will only return one node would be this:
MATCH (n)
RETURN n
LIMIT 1
In cypher land that will return you a map of the properties that the node has on it. If you want to get something more specific you could try this:
MATCH (n:Person)
RETURN n.name AS personName
LIMIT 1
So then you'd get a String back for that column in the result set.
-- Updating for Java API --
From the Java API you can write your own traversals which will give you back 'Node' and 'Relationship' objects. From those you'd then have to extract any properties that you're interested in.
try ( Transaction tx = graphDatabaseService.beginTx() )
{
ResourceIterable<Node> people = GlobalGraphOperations.at( graphDatabaseService ).getAllNodesWithLabel( DynamicLabel.label( "Person" ) );
for ( Node node : people )
{
String name = (String) node.getProperty( "name" );
}
tx.success();
}
Hi with cypher i can sugesst you few thing,
Q How to create a unique node i.e. guarantee uniqueness of a property?
Ans.
first chosse a property that could be unique for that node , same like Primary key in of your relational database system,
i.e Id
now you merge to create a node,
MERGE (u:User { Id:1 })
set u.Name='Charlie'
RETURN u
if the user with Id will not exist it will create it,
then using set Clause you can set other property or hole obejct as well,
Q Returning a node returns the complete database. How can I return just a node or a pojo list as JSON? Are there any working examples or explanation of Representation available?
Ans. Same way to match if you pass the unique id and try to search it will return you only that particualr node only i.e
match(u:User { Id:1 }) return u
to create such Id , i will suggest you to go with GUID created in programing lunguaze like C#,
but with neo4j 3.x you also used autoincremented propery as well.
Related
I have two graphs with node name as "URL" and Property as TC_1(for graph1), TC_2 (for graph2). Now I want to merge/collapse those two graphs to attain a network where merging will be done on the basis of equal node name and properties(TC_X) should be combined using apoc.
sc:API {URL: url , TC : "TC_002"})
Here URL is node of type API and TC is property.
MATCH (x:API)-[:NEXT]->(x:API)
WITH x, collect(x) as subgraph
CALL apoc.nodes.collapse(subgraph,{properties:'combine'}) yield from, rel, to
return from, rel, to
Code shows success but I do not get any output.
apoc.nodes.collapse create a single virtual node for the list of nodes passed and return it.
Virtual node means its created and returned to UI, but are not stored in the database.
So here code will show success but it will not change the database.
To make changes in the database you need to use apoc.refactor.mergeNodes instead of apoc.nodes.collapse.
Will Neo4j auto-generate unique ids for all the nodes created using 'CREATE' query, as 'id' in Mysql? We created a node with
CREATE (n: user{name:"x", age:10}) return n
If we want to update 'name' property, how to do it in Neo4j?
From the documentation though,
Searching for nodes by id can be done with the id() function in a predicate.
Neo4j reuses its internal ids when nodes and relationships are deleted. This means that applications using, and relying on internal Neo4j ids, are brittle or at risk of making mistakes. It is therefor recommended to rather use application generated ids.
It is a good idea to as they say, use Application generated ids that are stored as properties of the node. You need to set the application generated id while creating the node and then use that key on merge statements
MERGE (n:user{key:<myApplicationKey>}) return n
SET n.name="x", age=10
There is an internal id, you can access it the id() function
CREATE (n:User {name="x", age: 10}) RETURN n, id(n) as nodeId
Later on, you can update it with
MATCH (n) WHERE id(n) = 12345 SET n.name = "y"
I need to return nodes along with their IDs, and things like this are to be avoided:
RETURN n, ID(n) as n_ID
I would very much prefer to be able to return the ID as a "computed" property of the node, so that the client sees the node as if it had a property named id.
I've been breaking my head over this for hours now. The closest I found is this comment under an unsatisfying answer to a similar question:
MATCH (n:Person) RETURN { id: ID(n), name: n.name } as user
That method is useless because it requires manually reconstructing the node as a map literal in the RETURN clause. This is impossible if you don't know all the property names, which will be the typical scenario in my application; plus, there might be lots of properties.
Next thing I tried was operator '+'. It throws a Type Mismatch; you cannot combine a Map with a Node this way. I cannot find any documented way to convert a Node to a Map either. The docs mention KEYS(), but no VALUES(), nor a way to "zip" keys and values into a map.
Another thing I thought of trying:
REDUCE(theMap = {id: ID(n)}, k in KEYS(n) | theMap + { what? : what? })
... but I know neither how to do a "variable key" in an array literal, nor how to access a node's property by a variable key.
Is what I am trying to do at all possible in cypher?
You can add the id property right after you CREATE a node (and in the same transaction). For example:
CREATE (n:Person {name: "Fred", address: "123 Main St"})
SET n.id = ID(n)
RETURN n;
This way, your nodes will actually have an id node -- there is no need to compute it later.
Depending on what you are doing with the id, you might want to reconsider returning the Neo4j node id (the internal id) and instead generate and store a UUID property on each node. Internal node ids can be reused and should not be used to reference nodes in an external system. Internal ids represent an offset in the store file and if nodes are deleted these gaps in the store file can be filled in, reclaiming already used ids.
There is a plugin here that can automate UUID creation and a discussion on Github here.
I am using neo4j for one of my project, there's a node which only has a single property as name, I want to get that node using ID, it already has a ID but when I use this code
MATCH (s:SKILLS{ID:65110}) return s
It returns nothing, heres my node
If the query is wrong then how do I query it using the number
MATCH (s)
WHERE ID(s) = 65110
RETURN s
The ID function gets you the id of a node or relationship. This is different from any property called id or ID that you create.
START should only be used when accessing legacy indexes. It is disabled in Cypher 2.2 3.2 and up.
Neo4j recommends using WHERE ID(n) = , and furthermore states that it will only require a single lookup (does not scan every node to find the matching ID)
WARNING
The answer below is incorrect. It is listed for reference only. See the updated answer above (quoted). The text below is kept for reference only
You can use WHERE ID(s) = 65110, but this will check the ID of every node in your database.
There is a more efficient way to do this:
START s=NODE(517) MATCH(s) RETURN s
you can say:
(n:User) where id(n) >=20 RETURN n
this will return all nodes of type User with node reference ID more than 20
I have a relatively large set of nodes, and I want to find all pairs of nodes that have matching property values, but I don't know or care in advance what the property value is. This is basically an attempt to find duplicate nodes, but I can limit the definition of a duplicate to two or more nodes that have the same property value.
Any ideas how to proceed? Not finding any starting points in the neo4j docs. I'm on 1.8.2 community edition.
EDIT
Sorry for not being clear in the initial question, but I'm talking about doing this through Cypher.
Cypher to count values on a property, returning a collection of nodes as well:
start n=node(*)
where has(n.prop)
with n.prop as prop, collect(n) as nodelist, count(*) as count
where count > 1
return prop, nodelist, count;
Example on console: http://console.neo4j.org/r/k2s7aa
You can also do an index scan with the property like so (to avoid looking at nodes that don't have this property):
start n=node:node_auto_index('prop:*') ...
2.0 Cypher with a label Label:
match (n:Label)
with n.prop as prop, collect(n) as nodelist, count(*) as count
where count > 1
return prop, nodelist, count;
Update for 3.x: has was replaced by exists.
You can try this one who does which I think does whatever you want.
START n=node(*), m=node(*)
WHERE
HAS(n.name) AND HAS (m.name) AND
n.name=m.name AND
ID(n) <ID(m)
RETURN n, m
http://console.neo4j.org/?id=xe6wmt
Both nodes should have a name property. name should be equal for both nodes and we only want one pair of the two possibilites which we get via the id comparison. Not sure about performance - please test.
What about the following approach:
use getAllNodes to get an Iterable over all nodes.
using getPropertyKeys and getProperty(key) build up a java.util.Map containing all properties for a node. Calculate the map's hashCode()
build up a global Map using the hashCode as key and a set of node.getId() as values
This should give you the candidates for being duplicate. Be aware of the hashCode() semantics, there might be nodes with different properties mapping to the same hashCode.
Neo4j 3.1.1
HAS is no longer supported in Cypher, please use EXISTS instead.
If you want to find nodes with specific property, the Cyper is as follows:
MATCH (n:NodeLabel) where has(n.NodeProperty) return n
With Neo4j 3.3.4 you can simply do the following:
MATCH (n) where EXISTS(n.propertyName) return n
Simply change propertyName to whatever property you are looking to find.
The best/easiest option is to do something like a local Map. If you did something like this, you could create code like this:
GlobalGraphOperations ggo = GlobalGraphOperations.at(db);
Map<Object, Node> duplicateMap = new HashMap<Object, Node>();
for (Node node : ggo.getAllNodes()) {
Object propertyValue = node.getProperty("property");
Node existingNode = duplicateMap.get(propertyValue);
if (existingNode == null) {
duplicateMap.put(propertyValue, node);
} else {
System.out.println("Duplicate Node. First Node: " + existingNode + ", Second Node: " + node);
}
}
This would print out a list. If you needed to do more, like remove these nodes, you could do something in the else.
Do you know the property name? Will this be multiple properties, or just duplicates of a single name/value pair? If you are doing multiple properties, just create a map for each property you have.
You can also use an index on that property. Then for a given value retrieve all the nodes. The advantage is that you can also query for approximations of the value.