I am trying to create multiple nodes in Neo4j using Cypher by passing properties as parameters as part of an UNWIND function, but I keep receiving the error Type mismatch: expected Collection<T> but was Map.
This happens even when using the following example from the Neo4j documentation (link):
UNWIND {
props : [ {
name : "Andres",
position : "Developer"
}, {
name : "Michael",
position : "Developer"
} ]
} AS map
CREATE (n)
SET n = map
Can anyone point out what I am doing wrong here?
Note, the example above is not exactly as in the Neo4j documentation. Their example wraps the property names in double quotes, but this causes my instance of Neo4j to throw the errorInvalid input '"': expected whitespace...)
UNWIND is expecting a collection, not a map as you're currently passing in, try this instead (just remove the wrapping curly braces and prop top level field):
UNWIND [ {
name : "Andres",
position : "Developer"
}, {
name : "Michael",
position : "Developer"
} ] AS map
CREATE (n)
SET n = map
Chris's answer is of course the correct one, but here's why your solution doesn't work when you're following the documentation: you're not copying the documentation.
The documentation shows the use of a named parameter:
UNWIND { props } AS map
CREATE (n)
SET n = map
with props passed in the map of parameters, which would look like:
{
"props" : [ {
"name" : "Andres",
"position" : "Developer"
}, {
"name" : "Michael",
"position" : "Developer"
} ]
}
if you displayed the map as JSON. It means the {props} placeholder will be replaced by the value for the props key. Which is exactly what Chris did.
Here's what the Java code would look like:
GraphDatabaseService db = /* init */;
Map<String, Object> andres = new HashMap<>();
andres.put("name", "Andres");
andres.put("position", "Developer");
Map<String, Object> michael = new HashMap<>();
michael.put("name", "Michael");
michael.put("position", "Developer");
Map<String, Object> params = new HashMap<>();
params.put("props", Arrays.asList(andres, michael));
try (Transaction tx = db.beginTx()) {
db.execute("UNWIND {props} AS map CREATE (n) SET n = map", params);
tx.success();
}
Related
I'm looking for a query which can find all of the nodes which have properties that match a parameter which is an object. The properties of the node can be a superset (contain more properties than the filter)
e.g.
:param obj : { first : "first" }
CREATE (n:Test { first : "first", second : "second" });
CREATE (m:Test { first : "first" });
CREATE (f:Fail { first : "bad", second : "second" });
MATCH (c)
WHERE
PROPERTIES(c) = $obj
RETURN c;
n and m should be returned as they are matching on first : "first"
it is doable with apoc, basically by matching the obj with a submap of the properties, containing only the keys that are also present in obj
WITH { first : "first" } AS obj
MATCH (c)
WHERE apoc.map.submap(properties(c),keys(obj),[],false)= obj
RETURN c
I have a Neo4j DB with relationships that have properties such as [:FRIENDS {since: "11/2015"}]. I need to represent the "since" property in the GraphQl Schema. RELAY has something call "edges" an apparently this is how they implement this feature but I am not using RELAY.....I didn't see anything in Apollo (maybe I missed it). Can someone show me how to do this?
Ok...so in order to get what I wanted which was to present both the node and the relationship (edge) to graphql I did what I would call a work-around by returning object.assign(node,relationship) to graphql....the downside is that I have to define a type nodeRel {} to receive the combined objects but it works. Also, the node and relationship objects can't have similar named properties. I can now answer the question how long John and Mary are friends or what groups John belongs to and how long he has been a member....Schema snippet:
... memberOf : [Group]
groupStatus : [MemberProfile]
attended : [Meeting]
submittedReport : [Report]
post : [Post]
}
type MemberProfile {
name : String
location : String
created : String
since : String
role : String
financial : Boolean
active : Boolean
}
Resolver:
groupStatus(voter) {
let session = driver.session(),
params = { voterid: voter.voterid },
query = `
MATCH (v:Voter)-[r:MEMBER_OF]->(g:Group)
WHERE v.voterid = $voterid
RETURN g AS group,r AS rel;
`
return session
.run(query, params)
.then(result => {
return result.records.map(record => {
return Object.assign(record.get("group").properties, record.get("rel").properties)
})
})
},
I hope this help someone else....
I tried many things but of no use.
I have already raised a question on stackoverflow earlier but I am still facing the same issue.
Here is the link to old stackoverflow question
creating multiple nodes with properties in json in neo4j
Let me try out explaining with a small example
This is the query I want to execute
{
"params" : {
"props" : [
{
"LocalAsNumber" : 0,
"NodeDescription" : "10TiMOS-B-4.0.R2 ",
"NodeId" : "10.227.28.95",
"NodeName" : "BLR_WAO_SARF7"
}
]
},
"query" : "MATCH (n:Router) where n.NodeId = {props}.NodeId RETURN n"}
For simplicity I have added only 1 props array otherwise there are around 5000 props. Now I want to execute the query above but it fails.
I tried using (props.NodeId}, {props[NodeID]} but everything fails.
Is it possbile to access a individual property in neo4j?
My prog is in c++ and I am using jsoncpp and curl to fire my queries.
If you do {props}.nodeId in the query then the props parameter must be a map, but you pass in an array. Do
"props" : {
"LocalAsNumber" : 0,
"NodeDescription" : "10TiMOS-B-4.0.R2 ",
"NodeId" : "10.227.28.95",
"NodeName" : "BLR_WAO_SARF7"
}
You can use an array of maps for parameter either with a simple CREATE statement.
CREATE ({props})
or if you loop through the array to access the individual maps
FOREACH (prop IN {props} |
MERGE (i:Interface {nodeId:prop.nodeId})
ON CREATE SET i = prop
)
Does this query string work for you?
"MATCH (n:Router) RETURN [p IN {props} WHERE n.NodeId = p.NodeId | n];"
I am using json to create nodes in noe4j
I have written a small c++ prog to do so using curl and json
Now i have to create around 10000 nodes in neo4j with properties having name and value.
For that i am using props in json with the query as
{
"params" : {
"props" : {
[{name : "a", value : 1}, {name : "b", value : 2}......so on]
]
}
},
"query" : "CREATE (n:Router { props }) RETURN n"
}
the question is I just want to create that nodes with unique names. If a node is already present with the name as in json props I do not want to create it.
How to write a query for these types of request in neo4j
Change your query to the following:
{
"params" : {
"props" : {
[{name : "a", value : 1}, {name : "b", value : 2}......so on]
]
}
},
"query" : "FOREACH (router in {props} | MERGE (n:Router {name: router.name}) ON CREATE SET n = router)"
}
Basically it iterate the items in your list, check for name property if it exist and it case it save a new node
Some pseudo-code of the model I'm working with:
User { int Id, string Username }
Activity { int Id, string Name }
Place { int Id, string Name }
Basically I have a bunch of Users and they belong to certain places (many to many relationship in RDBMS world). What I'd like to do now that I've created all of the nodes already is create the relationship between them. To do that I believe I need to get references to each node and then simply create the relationship between them.
Note: So far no relationships exist. It does look like in some of the examples they have added the User nodes with a relationship that points to the RootNode but I have no idea why. I'm not sure if I need to do that or not.
More pseudo-code:
var userRef = _graphClient...GetUserNodeWhereIdEquals(user.Id);
// or something like _graphClient.OutV<User>("[[id={0}]]", user.Id)
// or even just _graphClient.V<User>(id == user.Id)
var placeRef = _graphClient...GetPlaceNodeWhereIdEquals(place.Id);
_graphClient...CreateRelationshipBetween(userRef, placeRef, "belongs_to");
Unfortunately the documentation starts off pretty great then goes south when you get to relationships.
Update 3/29/12
Here's the code I have so far:
foreach (var a in _activityTasks.GetAll())
{
_graphClient.Create(a, new ActivityBelongsTo(_graphClient.RootNode));
}
foreach (var p in _placeTasks.GetAll().Take(1))
{
var placeNode = _graphClient.Create(p, new PlaceBelongsTo(_graphClient.RootNode));
foreach (var activity in p.Activities)
{
Activity activity1 = activity;
var activityNode = _graphClient.RootNode.In<Activity>(ActivityBelongsTo.TypeKey, a => a.Id == activity1.Id).SingleOrDefault();
_graphClient.CreateRelationship(placeNode, new PlaceHasActivity(activityNode.Reference));
}
}
The activity nodes are created fine. The place node is created fine. An error is now being thrown when trying to get the activityNode. It's a rather large stack trace so I'll try to paraphrase here:
Received an exception when executing the request.
The query was: g.v(p0).in(p1).filter{ it[p2] == p3
}.drop(p4).take(p5)._()
The exception was: Value cannot be null. Parameter name: key
System.ArgumentNullException: Value cannot be null.Parameter name: key
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue
value, Boolean add) ... The raw response body was: [ {
"outgoing_relationships" :
"http://localhost:7474/db/data/node/2/relationships/out", "data" : {
"Name" : "Aerobics", "Id" : 2 }, "all_typed_relationships" :
"http://localhost:7474/db/data/node/2/relationships/all/{-list|&|types}",
"traverse" :
"http://localhost:7474/db/data/node/2/traverse/{returnType}", "self"
: "http://localhost:7474/db/data/node/2", "property" :
"http://localhost:7474/db/data/node/2/properties/{key}",
"outgoing_typed_relationships" :
"http://localhost:7474/db/data/node/2/relationships/out/{-list|&|types}",
"properties" : "http://localhost:7474/db/data/node/2/properties",
"incoming_relationships" :
"http://localhost:7474/db/data/node/2/relationships/in", "extensions"
: { }, "create_relationship" :
"http://localhost:7474/db/data/node/2/relationships",
"paged_traverse" :
"http://localhost:7474/db/data/node/2/paged/traverse/{returnType}{?pageSize,leaseTime}",
"all_relationships" :
"http://localhost:7474/db/data/node/2/relationships/all",
"incoming_typed_relationships" :
"http://localhost:7474/db/data/node/2/relationships/in/{-list|&|types}"
} ]
Something to do when adding a item to a Dictionary when the key is null. Problem is, I don't see any nulls when I debug on my end, activity1 is there, RootNode is there, TypeKey is a const string.
I'm almost wondering if I should just keep the created nodes within a array or Dictionary myself and then just working with the NodeReference. That's what I'm going to try next.
Later that morning
This seems to load everything into the graph database fine:
var activityNodes = _activityTasks.GetAll().ToDictionary(a => a.Id, a => _graphClient.Create(a, new ActivityBelongsTo(_graphClient.RootNode)));
foreach (var p in _placeTasks.GetAll())
{
var placeNode = _graphClient.Create(p, new PlaceBelongsTo(_graphClient.RootNode));
foreach (var activity in p.Activities)
{
_graphClient.CreateRelationship(placeNode, new PlaceHasActivity(activityNodes[activity.Id]));
}
}
foreach (var u in _userTasks.GetAllUserGraph())
{
var userNode = _graphClient.Create(u, new UserBelongsTo(_graphClient.RootNode));
foreach(var activity in u.Activities)
{
_graphClient.CreateRelationship(userNode, new UserParticipatesIn(activityNodes[activity.Id]));
}
}
Now the problem is similar to what I had before. Now I want to get an activity that has a relationship to the RootNode:
Node<Activity> activity = _graphClient
.RootNode
.In<Activity>(ActivityBelongsTo.TypeKey, a => a.Id == 1)
.SingleOrDefault();
Throwing the key value can't be null exception again. I think I need to investigate the gremlin syntax more. I'm guessing the problem is there.
This afternoon
Started to experiment with Gremlin queries:
g.v(0).inE.filter{it.label=="ACTIVITY_BELONGS_TO"}.outV.filter{it.Id==1}.Name
works fine. I tried to replicate that using neo4jClient syntax:
_graphClient.RootNode.InE(ActivityBelongsTo.TypeKey).OutV(b => b.Id == 1).SingleOrDefault();
Same null exception, it spits out:
g.v(p0).inE.filter{ it[p1].equals(p2) }.outV.filter{ it[p3] == p4 }.drop(p5).take(p6)._()
which looks right to me, except for the end. Ran this though:
g.v(0).inE.filter{it.label=="ACTIVITY_BELONGS_TO"}.outV.filter{it.Id==1}.drop(0).take(1)._()
And that works fine. Something stinks here...maybe I should try the other library although I liked the de/serialization support. Sigh...
Thought maybe a raw query would work. Nope! This method no longer accepts a string and the required GremlinQuery I have no idea how to you. Grooooooooooooooooan.
var users = graphClient.ExecuteGetAllNodesGremlin<IsCustomer>("g.v(0).out('IsCustomer'){it.'Name' == 'BobTheBuilder'}");
Update 3/30/12
Created a new project, everything below works fine. Super confused why it will work here... :( Maybe version differences, I have no idea.
var client = new GraphClient(new Uri("http://localhost:7474/db/data"));
client.Connect();
client.Create(new User { Id = 1, Username = "joe" }, new UserBelongsTo(client.RootNode));
client.Create(new User { Id = 2, Username = "cloe" }, new UserBelongsTo(client.RootNode));
client.Create(new Activity { Id = 1, Name = "Bocce Ball" }, new ActivityBelongsTo(client.RootNode));
client.Create(new Activity { Id = 2, Name = "Programming" }, new ActivityBelongsTo(client.RootNode));
var user = client.RootNode.In<User>(UserBelongsTo.TypeKey, u=>u.Id == 1).SingleOrDefault();
var activity = client.RootNode.In<Activity>(ActivityBelongsTo.TypeKey, a=>a.Id == 1).SingleOrDefault();
client.CreateRelationship(user.Reference, new Plays(activity.Reference));
user = client.RootNode.In<User>(UserBelongsTo.TypeKey, u => u.Id == 1).SingleOrDefault();
activity = client.RootNode.In<Activity>(ActivityBelongsTo.TypeKey, a => a.Id == 1).SingleOrDefault();
I'm just getting started too. I would suggest you check out this blog:
http://romikoderbynew.com/2011/07/30/neo4jclient-primer/
Also, check http://frictionfree.org and its source code (in the about section) for more examples.
Creating relationships on existing - as I understand, this is possible. However, it appears to be easier to associate nodes as you create them. From the blog:
You can also create relationships between existing nodes.
graphClient.CreateRelationship(customerNodeReference, new
Speaks(languageNode.Reference));
RootNode - I believe you need to start a query from a node, I don't think you can do a
SELECT * FROM ... WHERE
Therefore, it would make sense that you need to attach nodes to the root node. This is an example from the FrictionFreeApp:
var node = graphClient.Create(
user,
new UserBelongsTo(rootNode));