Question

I have a method for "Likes" in my contrived social app. It looks like this: (split it up for looking at the query text before I send it off to be executed (was using executewihoutresults)

var client = new GraphClient(new Uri("http://localhost:7474/db/data"));

client.Connect();

var q = client.Cypher.Start(new {n = string.Format("node({0})", nodeId)})
      .Match("(u:User)")
      .Where((User u) => u.ProviderUserKey == id)
      .Create("(n)-[:Liked_By]->(u)");
var res = q.Return(u => u.As<UserInfo>()).Results;

This produces something like this in cypher:

START n=node(31)
MATCH (u:User)
WHERE (u.ProviderUserKey = 9)
CREATE (n)-[:Liked_By]->(u)

When I execute it from the web console, it gives me the expected behavior of creating a relationship between a node (n) and a user node (u). However when I execute it from .net, it creates a new node for user, and a new relationship for whatever node I started at.

I'm relatively new, so I'm hoping this is blindingly obvious! How can I write this query so that it will create only a relationship between the node (which can be of any time) to the user node?

Full project available at https://github.com/fauxtrot/angular-ts-proto

Was it helpful?

Solution

What version of the .NET client are you using?

Given that your Cypher above is making use of labels, it looks like you're using a fairly recent version of Cypher/Neo4j, e.g. Cypher 2 and Neo4j 2.x.

If you're using Cypher 2 (and the .NET client supports it), see what happens when you update the query to something like this:

MATCH (u:User {ProviderUserKey: 9}), (n {id: 31})
CREATE (n)-[:Liked_By]->(u)

...and translate that to what the .NET client uses (I've not done much with the .NET Neo4j client at this point).

To be honest, if you're looking to only generate that relationship once, consider using MERGE instead of CREATE (again, if you're using Cypher 2).

To me, it sounds like the .NET statement isn't generating Cypher where the graph recognizes the User node, and so it's being created (hope that doesn't sound too obvious).

Let us know how it goes.

OTHER TIPS

So this was a lesson learned on what the Merge keyword actually does. In a previous query, I was Merging what I thought were two queries to get the likes for an item, after querying for the item. The Merge statement was creating a new user node per like with a like relationship.

I did rewrite the query that I spoke of above and have something that looks like this:

client.Cypher
  .Start(new { n = string.Format("node({0})", nodeId) })
  .Match("(u:User {ProviderUserKey : {id}})")
  .WithParam("id", id)
  .Create("(n)-[:Liked_By]->(u)").ExecuteWithoutResults();

Which has the desired effect of only creating a relationship. Thank you to @BtySgtMajor for getting my on the right track to figure this out (by mentioning the relationship.

For those playing along at home here was the offending query:

  var result = client.Cypher.Start(new { s = string.Format("node({0})", id) })
               .Match("(u:User)<-[mb:Created_By]-(c:Comment)-[o:On_Item]->(s:Session)")
               .Merge("(c)-[lb:Liked_By]->(lbu:User)")  //bad line here
               .Return((u, mb, c, s, o, lbu) => 
                     new { Comment = c.As<Comment>(), MadeByUser = u.Node<UserInfo>(),                  CommentNodeId = c.Id(), LikedByUsers = lbu.CollectAs<UserInfo>() })
                           .Results.Select(x =>
                           {
                               x.Comment.MadeBy = x.MadeByUser.Data;
                               x.Comment.MadeBy.NodeId = (int)x.MadeByUser.Reference.Id;
                               x.Comment.MadeBy.ProviderUserKey = x.MadeByUser.Reference.Id;
                               x.Comment.Id = (int)x.CommentNodeId;
                               x.Comment.LikedBy = x.LikedByUsers.Select(ui => new UserInfo { Username = ui.Data.Username, ProviderUserKey = ui.Reference.Id, NodeId = (int)ui.Reference.Id }).ToList();
                               return x.Comment;
                           });

I changed the Merge to an OptionalMatch and it was no longer creating the errant user nodes!

However, I feel this is not a clean implementation, and that there is a better way to write this query. I'll raise it in another question.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top