I created the following nodes and relationship in neo4j
CREATE (United_States:Citizenship { type : “Naturalized”})
CREATE (United_States:Citizenship { type : “Native_Born”})
CREATE (uid:Person { unique_id: 'A23AF39D-BEED-4FFC-B080-1362920FA7A8', id_type: '128bit_UUID' })
MATCH (uid:Person),(Native_Born:Citizenship) WHERE uid:Person="A23AF39D-BEED-4FFC-B080-1362920FA7A8" CREATE (uid) <- [ r:PersonUniqueIdentifier ] -> (Native_Born)
CREATE (fn:Person { first_name:'Willie', id_type:'128bit_UUID'})
CREATE (ln:Person { last_name:'Armstrong', id_type:'128bit_UUID'}))
CREATE CONSTRAINT ON (uid:Person) ASSERT Person.unique_id IS UNIQUE
CREATE INDEX ON :Person(unique_id)
I do not see the 'PersonUniqueIdentifier' Relation between the Citizenship node and id:Person node on the graph.
Screen shot of graph
Firstly, I would make a habit of doing the indexes/constraints first. There's not a lot of data here, but if you add an index after adding the data, it will need to go through all your nodes first. Also, creating a constraint also adds an index for you, so no need for that line. It seems like you're mixing up variables here, so refactoring a bit:
CREATE CONSTRAINT ON (person:Person) ASSERT person.unique_id IS UNIQUE
Also your Citizenship CREATEs are using the same variable name. I don't know if that would necessarily cause a problem, but it's simpler to do this anyway:
CREATE (:Citizenship { type : “Naturalized”}), (:Citizenship { type : “Native_Born”})
This statement looks fine to me (though, again, you could lose the variable if you wanted to):
CREATE (person:Person { unique_id: 'A23AF39D-BEED-4FFC-B080-1362920FA7A8', id_type: '128bit_UUID' })
Here there are a few problems. Here's how I would refactor it:
MATCH (person:Person),(citizenship:Citizenship)
WHERE
person.unique_id="A23AF39D-BEED-4FFC-B080-1362920FA7A8",
citizenship.type = 'Native_Born'
CREATE (person)-[:HAS_CITIZENSHIP]->(citizenship)
I'm not really sure what you want to do here. It seems like you want to create one person, so I would do this:
CREATE (:Person { first_name:'Willie', id_type: '128bit_UUID', last_name:'Armstrong'})
Related
I am importing some .cvs files for my database in neo4j, but I have the data of people in three different files, so when I import the data of the person from another file that has more data, I get an error when trying to import people nodes, because I already have other nodes with those dni (constraint) in my database.
So I want to create the new node or, if it exists, retrieve its pointer to create relationships with other nodes that I keep creating while I import.
I have tried several things on the internet but I still can't find the solution
Here my code:
LOAD CSV WITH HEADERS FROM 'file:/D:/ACCOUNT.csv' AS line FIELDTERMINATOR ';'
MERGE (persona :Persona { dni: line.DNI,
nombre: line.NOMBRE,
sexo: line.SEXO,
fechaNacimiento: line.FNACIMIENTO,
direccion: line.DIRECCION
})
I have tried with apoc and "with" but I still can't find the solution.
when this code finds another node with a person label and ID equal to the one entered, it gives me an error
To get this working, you'll have to understand how MERGE works. The statement
MERGE (persona :Persona { dni: line.DNI, nombre: line.NOMBRE, sexo: line.SEXO,
fechaNacimiento: line.FNACIMIENTO,direccion: line.DIRECCION
})
will create a new Persona node for every distinct combination of the above properties. So, for a node with the same dni, but with other values of other properties, this will fail. To fix this, you should try merging the nodes on the basis of their dni, and then set the properties like this:
MERGE (persona :Persona { dni: line.DNI })
ON CREATE
SET persona.nombre = line.NOMBRE,
persona.sexo = line.SEXO,
persona.fechaNacimiento = line.FNACIMIENTO,
persona.direccion = line.DIRECCION
The above query will ignore setting properties if a matching node is found. To set some properties when a match is found, use ON MATCH, like this:
MERGE (persona :Persona { dni: line.DNI })
ON CREATE
SET persona.nombre = line.NOMBRE,
persona.sexo = line.SEXO,
persona.fechaNacimiento = line.FNACIMIENTO,
persona.direccion = line.DIRECCION
ON MATCH
// Matching logic here
I have the following paramObj and dbQuery
paramObj = {
email: newUser.email,
mobilenumber: newUser.telephone,
password: newUser.password,
category: newUser.category,
name: newUser.name,
confirmuid: verificationHash,
confirmexpire: expiryDate.valueOf(),
rewardPoints: 0,
emailconfirmed: 'false',
paramVehicles: makeVehicleArray,
paramVehicleProps: vehiclePropsArray
}
dbQuery = `CREATE (user:Person:Owner {email:$email})
SET user += apoc.map.clean(paramObj,
['email','paramVehicles','paramVehiclesProps'],[])
WITH user, $paramVehicles AS vehicles
UNWIND vehicles AS vehicle
MATCH(v:Vehicles {name:vehicle})
CREATE UNIQUE (user)-[r:OWNS {since: timestamp()}]->(v)
RETURN user,r,v`;
Then I tried to execute
commons.session
.run(dbQuery, paramObj)
.then(newUser => {
commons.session.close();
if (!newUser.records[0]) {........
I am getting
Error: {"code":"Neo.ClientError.Statement.SyntaxError","name":"Neo4jError"}
which doesn't direct me anywhere. Can anyone tell me what am I doing wrong here?
This is actually the first time I am using the query format .run(dbQuery, paramObj) but this format is critical to my use case. I am using Neo4j 3.4.5 community with apoc plugin installed.
Ok...so I followed #inversFalcon suggestion to test in browser and came up with following parameters and query that closely match the ones above:
:params paramObj:[{ email:"xyz123#abc.com", mobilenumber:"8711231234",password:"password1", category:"Owner",name:"Michaell",vehicles:["Toyota","BMW","Nissan"],vehicleProps: [] }]
and query
PROFILE
CREATE (user:Person:Owner {email:$email})
SET user += apoc.map.clean($paramObj, ["email","vehicles","vehicleProps"],[])
WITH user, $vehicles AS vehicles
UNWIND vehicles AS vehicle
MATCH(v:Vehicles {name:vehicle})
MERGE (user)-[r:OWNS {since: timestamp()}]->(v)
RETURN user,r,v;
Now I get
Neo.ClientError.Statement.TypeError: Can't coerce `List{Map{name -> String("Michaell"), vehicles -> List{String("Toyota"), String("BMW"), String("Nissan")},.......
I also reverted to neo4j 3.2 (re: an earlier post by Mark Needham) and got the same error.
You should try doing an EXPLAIN of the query using the browser to troubleshoot it.
A few of the things I'm seeing here:
You're referring to paramObj, but it's not a parameter (rather, it's the map of parameters you're passing in, but it itself is not a parameter you can reference in the query). If you need to reference the entire set of parameters being passed in, then you need to use nested maps, and have paramObj be a key in the map that you pass as the parameter map (and when you do use it in the query, you'll need to use $paramObj)
CREATE UNIQUE is deprecated, you should use MERGE instead, though be aware that it does behave in a different manner (see the MERGE documentation as well as our knowledge base article explaining some of the easy-to-miss details of how MERGE works).
I am not sure what caused the coercion error to disappear but it did with the same query and I got a "expected parameter error" this was fixed by using $paramObj.email, etc. so the final query looks like this:
CREATE (user:Person:Owner {email: $paramObj.email})
SET user += apoc.map.clean($queryObj, ["email","vehicles","vehicleProps"],[])
WITH user, $paramObj.vehicles AS vehicles
UNWIND vehicles AS vehicle
MATCH(v:Vehicles {name:vehicle})
MERGE (user)-[r:OWNS {since: timestamp()}]->(v)
RETURN user,r,v;
which fixed my original problem of how to remove properties from a map when using SET += map.
I have a question about the query based on the predefined constraints in PopotoJs. In this example, the graph can be filtered based on the constraints defined in the search boxes. The sample file in this example visualizations folder, constraint is only defined for "Person" node. It is specified in the sample html file like the following:
"Person": {
"returnAttributes": ["name", "born"],
"constraintAttribute": "name",
// Return a predefined constraint that can be edited in the page.
"getPredefinedConstraints": function (node) {
return personPredefinedConstraints;
},
....
In my graph I would like to apply that query function for more than one node. For example I have 2 nodes: Contact (has "name" attribute) and Delivery (has "address" attribute)
I succeeded it by defining two functions for each nodes. However, I also had to put two search box forms with different input id (like constraint1 and constraint2). And I had to make the queries in the associated search boxes.
Is there a way to make queries which are defined for multiple nodes in one search box? For example searching Contact-name and/or Delivery-adress in the same search box?
Thanks
First I’d like to specify that the predefined constraints feature is still experimental (but fully functional) and doesn’t have any documentation yet.
It is intended to be used in configuration to filter data displayed in nodes and in the example the use of search boxes is just to show dynamically how it works.
A common use of this feature would be to add the list of predefined constraint you want in the configuration for every node types.
Let's take an example:
With the following configuration example the graph will be filtered to show only Person nodes having "born" attribute and only Movie nodes with title in the provided list:
"Person": {
"getPredefinedConstraints": function (node) {
return ["has($identifier.born)"];
},
...
}
"Movie": {
"getPredefinedConstraints": function (node) {
return ["$identifier.title IN [\"The Matrix\", \"The Matrix Reloaded\", \"The Matrix Revolutions\"]"];
},
...
}
The $identifier variable is then replaced during query generation with the corresponding node identifier. In this case the generated query would look like this:
MATCH (person:`Person`) WHERE has(person.born) RETURN person
In your case if I understood your question correctly you are trying to use this feature to implement a search box to filter the data. I'm still working on that feature but it won't be available soon :(
This is a workaround but maybe it could work in your use case, you could keep the search box value in a variable:
var value = d3.select("#constraint")[0][0].value;
inputValue = value;
Then use it in the predefined constraint of all the nodes type you want.
In this example Person will be filtered based on the name attribute and Movie on title:
"Person": {
"getPredefinedConstraints": function (node) {
if (inputValue) {
return ["$identifier.name =~ '(?i).*" + inputValue + ".*'"];
} else {
return [];
}
},
...
}
"Movie": {
"getPredefinedConstraints": function (node) {
if (inputValue) {
return ["$identifier.title =~ '(?i).*" + inputValue + ".*'"];
} else {
return [];
}
},
...
}
Everything is in the HTML page of this example so you can view the full source directly on the page.
#Popoto, thanks for the descriptive reply. I tried your suggestion and it worked pretty much well. With the actual codes, when I make a query it was showing only the queried node and make the other node amount zero. I wanted to make a query which queries only the related node while the number of other nodes are still same.
I tried a temporary solution for my problem. What I did is:
Export the all the node data to JSON file, search my query constraint in the exported JSONs, if the file is existing in JSON, then run the query in the related node; and if not, do nothing.
With that way, of course I needed to define many functions with different variable names (as much as the node amount). Anyhow, it is not a propoer way, bu it worked for now.
I'm novice in Neo4j and cypher and would like some help solving an issue. All help would be appreciated.
This is my problem:
I have created two nodes, one as a user and one as a city, linked to the user.
Graph setup
CREATE (n:User{firstName : "John", lastName : "Doe"});
MATCH (user:User{firstName : "John", lastName : "Doe"})
Return user;
Query:
MATCH (user:User)
WHERE user.firstName = "John"
CREATE (city:City { cityName:"Liverpool", areaCode:"34343" })
CREATE (user)-[:STUDY_IN]->(city);
Now I want to create a new node(user) and link that user to the existing node (city:Liverpool).
I've done that i this way:
MATCH (city:City)
WHERE city.cityName = "Liverpool"
CREATE (user:User { firstName : "Kent", lastName : "Clark" })
CREATE (user)-[:STUDY_IN]->(city);
In real life, I would need to check if the city exist, before creating the relationship and if it doesn't exist, then I would like to create a new node for that city.
You can see my code here:
http://console.neo4j.org/?id=utor92
Use the MERGE command which will match a pattern if it exists or create it if it doesn't.
CREATE (user:User{firstName: "Kent", lastName: "Clark"})
MERGE (city:City{cityName: "Liverpool"})
CREATE (user)-[:STUDY_IN]->(city)
RETURN user, city
You can also use ON CREATE and ON MATCH with MERGE. For example:
MERGE (city:City{cityName: "Manchester"})
ON CREATE SET city.foo = "bar"
ON MATCH SET city.baz = "qux"
In this example if city does not exist it will be created and the property foo is set to "bar". If it exists already the property baz gets set to "qux".
For a more in depth look at MERGE check out the docs.
I have a Neo4j database containing information on Congressmen. The problem I'm having is if there is a vacant position. When this happens I am using the same key:value in the "Congressmen" index. I tried the code below because in the py2neo documentation it states that the add function is idempotent
#Check if we have any vacancies and if so if they match the one that we currently want to add
query="start n=node:Congressmen('website:N/A') return n"
result= cypher.execute(graph_db, query.encode('utf-8', errors='ignore'))
#Match what we already have
if str(result[0]) != "[]":
#create is idempotent so will only create a new node if properties are different
rep, = graph_db.create({"name" : userName, "website" : web, "district" : int(district), "state" : child[2].text, "party" : child[4].text, "office" : child[5].text, "phone" : child[6].text, "house" : "House of Representatives"})
cong = graph_db.get_or_create_index(neo4j.Node, "Congressmen")
# add the node to the index
cong.add("website", web, rep)
When I checked the interface after running the code 3 times I have duplicate nodes.
Is it possible to prevent the nodes from duplicating and still be able to index them using the same key/value?
The Index.add method is certainly idempotent: the same entity can only be added once to a particular entry point. The GraphDatabaseService.create method is not however. Each time you run the create method, a new node is created and each run of add appends that new node to the index. You probably want to use the Index.add_if_none, Index.create_if_none or Index.get_or_create method instead.