Auto-generation of id in Neo4j - neo4j

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"

Related

Unwind array and match with other nodes using Cypher on Neo4j graph database

I'm creating an app using GRANDstack on top of a Neo4j graph database and I'm struggling with writing a query that unwinds a property array, matches some IDs, pullsback names associated with the IDs and repackages them into a new array.
Essentially, I have Memory nodes (Mems) and Person nodes (Person) and their relationship is as follows: (Mems)-[WITH]->(Person). i.e. you can have a memory of something where you were WITH multiple people. The Mems nodes contain a personID property that is an array of IDs and the relationship in the graph database is built from the array of personIDs in Mems nodes that match the personIDs in the Person nodes.
The result I'm trying to achieve is like the below, however I haven't found a way to return the nicknames from the Person nodes:
The query I'm using to generate the above is below:
MATCH (m:Mem)-[WITH]->(p:Person)
WHERE m.personID IS NOT NULL
UNWIND m.personID as personID
CALL {
WITH personID
MATCH (p:Person)
WHERE personID = p.personID
RETURN p.nickname
}
RETURN m.mem, m.date, personID, p.nickname
I think it's close to what I need but I just can't figure out the last bit where I can return the nicknames associated with the personIDs. This might be something that APOC is more capable of doing?
[UPDATED]
This should work for you:
MATCH (m:Mem)-[:WITH]->(p:Person)
WHERE p.personID IN m.personID
RETURN m.mem, m.date, p.personID, p.nickname
Also, notice that the relationship pattern must use:WITH instead of WITH if you want to query for the WITH relationship type.
Addendum
Of course, since you have the WITH relationships, you should consider deleting the redundant m.personID property. You should get the same results without m.personID this way:
MATCH (m:Mem)-[:WITH]->(p:Person)
RETURN m.mem, m.date, p.personID, p.nickname

Is matching with id performant in Neo4J?

I'm wondering, when I have read the data of a node and I want to match it in another query, which way will have the best performance? Using id like this:
MATCH (n) WHERE ID(n) = 1234
or using indices of the node:
MATCH (n:Label {SomeIndexProperty: 3456})
Which one is better?
IDs are a technical ID for Neo4j, and those should not be used as a primary key for your application.
Every node (and relationship) has a technical ID, and it's stable over time.
But if you delete a node, for example the node 32, Neo4j will reuse this ID for a new node.
So you can use it in your queries inside the same transaction (there is no problem), otherwise you should know what you are doing.
The only way to retrieve the technical ID, is to use the function ID like you do on your first query : MATCH (n) WHERE ID(n) = 1234 RETURN n.
The ID is not exposed as a node's property, so you can't do MATCH (n {ID:1234}) RETURN n.
You have noticed that if you want to do a WHERE on a strict equality, you can do put the condition directly on the node.
For example :
MATCH (n:Node) WHERE n.name = 'logisima' RETURN n
MATCH (n:Node {name:'logisima'}) RETURN n
Those two queries are identicals, they generate the same query plan, it's just a syntactic sugar.
Is it faster to retrieve a node by its ID or by an indexed property ?
The easier way to know the answer to this question is to profile the two queries.
On the one based on the ID, you will see the box NodeByIdSeek that cost 1 db hit, and on the one with a unique constrainst you will see the box NodeUniqueIndexSeek with 2 db hits.
So searching a node by its ID is faster.

Neo4j query node property.

I have database with entities person (name,age) and project (name).
can I query the database in cypher that specifies me it is person or project?
for example consider I have these two instances for each :
Node (name = Alice, age= 20)
Node (name = Bob, age = 31)
Node (name = project1)
Node (name = project2)
-I want to know, is there any way that I just say project1 and it tells me that this is a project.
-or I query Alice and it says me this is a person?
Thanks
So your use case is to search things by name, and those things can be of several types instead of a single type.
Just to note, in general, this is not what Neo4j is built for. Typically in Neo4j queries you know the type of the thing you're searching for, and you're exploring relationships between that thing (or things) to figure out associations or data derived from that.
That said, there are ways to do this, though it's worth going through the rest of your use cases and seeing if Neo4j is really the best tool for what you're trying to do
Whenever you're querying by a property, you either want a unique constraint on the label/property, or an index on the label/property. Note that you need a combination of a label and a property for this; you cannot blindly ask for a node with a property without specifying a label and get good performance, as it will have to do a scan of all nodes in your database (there are some older manual indexes in Neo4j, but I'm not sure if these will continue to be supported; the schema indexes are recommended by the developers).
There is a workaround to this, as Neo4j allows multiple labels on the same node. If you only expect to query certain types by name (for example, only projects and people), you might create a :Named label, and set that label on all :Project and :Person nodes (and any other labels where it should apply). You can then create an index on :Named.name. That way your query would be something like:
MATCH (n:Named)
WHERE n.name = 'blah'
WITH LABELS(n) as types
WITH FILTER(type in types WHERE type <> 'Named') as labels
RETURN labels
Keep in mind that you haven't specified if a name should be unique among node types, so it could be possible for a :Person or a :Project or multiple :Persons to have the same name, unsure how that affects what should happen on your end. If every named thing ought to have a unique name, you should create a unique constraint on :Named.name (though again, it's on you to ensure that every node you create that ought to be :Named has the :Named label applied on creation).
You should use node labels (like Person and Project) to represent node "types".
For example, to create a person and a project:
CREATE (:Person {name: 'Alice', age: 20})
CREATE (:Project {name: 'project1'})
To find the project(s) named 'Fred':
MATCH (p:Project {name: 'Fred'})
RETURN p;
To get a collection of the labels of node n, you can invoke the LABELS(n) function. You can then look in that collection to see if the label you are looking for is in there. For example, if your Cypher query somehow obtains a node n, then this snippet would return n if and only if it has the Person label:
.
.
.
WHERE 'Person' IN LABELS(n)
RETURN n;
[UPDATED]
If you want to find all nodes with the name property value of "Fred":
MATCH (n {name: 'Fred'})
...
If you want to find all relationships with the name property value of "Fred":
MATCH ()-[r {name: 'Fred'})-()
...
If you want to match both in a single query, you have many ways to do that, depending on your exact use case. For example, if you want a cartesian product of the matching nodes and relationships:
OPTIONAL MATCH (n {name: 'Fred'})
OPTIONAL MATCH ()-[r {name: 'Fred'})-()
...

Return node with unknown-at-query-time structure, with a "computed" property added?

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.

Neo4J get node by ID

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

Resources