Neo4j How can I return both node and relationship? - neo4j

I am using Neo4jClient to write a demo. My demo has two nodes : Beer and BeerBrand and one relationship Is_Made has propertise ReleaseDay. I wrote this code to get nodes BeerBrand which made specific beer.
var isMadeBy = beer
.StartCypher("b")
.Match("b-[r:IS_MADE]->e")
.Return<Node<BeerBrand>>("e")
.Results.ToList();
Now, I want to get relationship *Is_Made*
var isMadeBy = beer
.StartCypher("b")
.Match("b-[r:IS_MADE]->e")
.Return<Relationship<IsMade>>("r")
.Results.ToList();
But, errors were thrown that
class IsMade must be non-abstract type with a public parameterless constructor
in order to use it as parameters 'TData' in the generic type or
method 'Neo4jClient.Relationship<TData>'
Can you help me to solve this problem?

There is an answer to a similar question here: Neo4jClient - Retrieving relationship from Cypher query which will give you the guide you should follow.
In essence, you need to add a Parameterless constructor to your relationship to allow the client (and in particular - JSON.NET) to be able to deserialize your relationship from what is in the DB to your code. Basically - JSON.NET can't figure out how to construct your relationship, as it doesn't know what the parameters in your constructors relate to.
You may also need to change from returning 'Relationship' to 'RelationshipInstance'.

Did you have a look at the wiki? http://hg.readify.net/neo4jclient/wiki/cypher
If you don't need the relationship Id then give that a try:
var isMadeBy = beer
.StartCypher("b")
.Match("b-[r:IS_MADE]->e")
.Return((r, e) => new {
isMadeRelationship = r.As<Node<SomeObjectWithAPublicConstructor>>()
beerBrand = e.As<Node<BeerBrand>>()
})
.Results.ToList();

Related

Spring data for neo4j generating dynamic relationships between entities

I just started reading and playing with graph db and specifically Neo4j.
However I didn't encounter a solution for a use case that seems to me very common. Assume I have User object in my system and I want to maintain the relationships between users.
Examples:
User1 -> User2 - relationship sibling
UserX -> UserY - relationship parent
UserY -> UserX - relationship child
UserX -> UserZ - relationship teacher
I would like to store the relationship (the edge between the nodes) dynamically and not creating an entity with all possible relationships entities with annotation #Relationship.
Later, I would like to get a user and all his connections, but in run-time to figure out what is the type of the relationship.
Is this possible with spring data? or maybe it is not possible at all using Neo4j?
I will appreciate if you can point me to some reading for a solution to my problem.
Thank you.
It seems that you are only interested in the type of relationship after you would query for all, right?
You could use a #RelationshipEntity and add a property to it to define its type.
#RelationshipEntity(type = "USER_RELATION")
public class UserRelation {
//... #StartNode/#EndNode/#Id
private String type; // Here goes sibling, parent, etc.
}
And in your User entity you would just define one relationship.
#Entity
public class User {
// ... id, etc.
#Relationship(type = "USER_RELATION")
private List<UserRelation> userRelations;
}
This would always query every outgoing connection to another user.

Breezejs projection not working for referencing one to many navigators

I have the following model:
1 Person to many Participant ('enrollments' is the navigator)
If I just want the name of the person, and the date of all enrollments, this doesn't work:
EntityQuery.from('Person').where('id','eq',id)
.select('firstName, lastName, enrollments.dateEnrolled')
.execute()
I get an error:
Unable to locate property 'DateEnrolled' on type
'System.Collections.Generic.ICollection`1[EntityClasses.Participant]'
What is the proper syntax for projections of fields on one-to-many relationships?
There is no really good way to express this in a single query. You can get all of the "enrollments" but you will need to select out the "dateEnrolled" on the client.
EntityQuery.from('Person').where('id','eq',id)
.select('firstName, lastName, enrollments').expand("enrollments")
.execute().then(function(data) {
// extract "dateEnrolled" from data.results
});
Alternatively, you can use a 'named query" on the server that performs the projection there and simply query the projection from the client.
Or perhaps better would be to invert your query. Something like this: ( assuming you have a scalar property named 'Person' on your 'Enrollment' type).
EntityQuery.from('Enrollments').where('person.id','eq',id)
.select('person.firstName, person.lastName, dateEnrolled').expand("person")
.execute().then(...);
I got this working on my fork of breeze.server.net: https://github.com/eggers/breeze.server.net/tree/property-of-collection-25

Neo4jClient: doubts about CRUD API

My persistency layer essentially uses Neo4jClient to access a Neo4j 1.9.4 database. More specifically, to create nodes I use IGraphClient#Create() in Neo4jClient's CRUD API and to query the graph I use Neo4jClient's Cypher support.
All was well until a friend of mine pointed out that for every query, I essentially did two HTTP requests:
one request to get a node reference from a legacy index by the node's unique ID (not its node ID! but a unique ID generated by SnowMaker)
one Cypher query that started from this node reference that does the actual work.
For read operations, I did the obvious thing and moved the index lookup into my Start() call, i.e.:
GraphClient.Cypher
.Start(new { user = Node.ByIndexLookup("User", "Id", userId) })
// ... the rest of the query ...
For create operations, on the other hand, I don't think this is actually possible. What I mean is: the Create() method takes a POCO, a couple of relationship instances and a couple of index entries in order to create a node, its relationships and its index entries in one transaction/HTTP request. The problem is the node references that you pass to the relationship instances: where do they come from? From previous HTTP requests, right?
My questions:
Can I use the CRUD API to look up node A by its ID, create node B from a POCO, create a relationship between A and B and add B's ID to a legacy index in one request?
If not, what is the alternative? Is the CRUD API considered legacy code and should we move towards a Cypher-based Neo4j 2.0 approach?
Does this Cypher-based approach mean that we lose POCO-to-node translation for create operations? That was very convenient.
Also, can Neo4jClient's documentation be updated because it is, frankly, quite poor. I do realize that Readify also offers commercial support so that might explain things.
Thanks!
I'm the author of Neo4jClient. (The guy who gives his software away for free.)
Q1a:
"Can I use the CRUD API to look up node A by its ID, create node B from a POCO, create a relationship between A and B"
Cypher is the way of not just the future, but also the 'now'.
Start with the Cypher (lots of resources for that):
START user=node:user(Id: 1234)
CREATE user-[:INVITED]->(user2 { Id: 4567, Name: "Jim" })
Return user2
Then convert it to C#:
graphClient.Cypher
.Start(new { user = Node.ByIndexLookup("User", "Id", userId) })
.Create("user-[:INVITED]->(user2 {newUser})")
.WithParam("newUser", new User { Id = 4567, Name = "Jim" })
.Return(user2 => user2.Node<User>())
.Results;
There are lots more similar examples here: https://github.com/Readify/Neo4jClient/wiki/cypher-examples
Q1b:
" and add B's ID to a legacy index in one request?"
No, legacy indexes are not supported in Cypher. If you really want to keep using them, then you should stick with the CRUD API. That's ok: if you want to use legacy indexes, use the legacy API.
Q2.
"If not, what is the alternative? Is the CRUD API considered legacy code and should we move towards a Cypher-based Neo4j 2.0 approach?"
That's exactly what you want to do. Cypher, with labels and automated indexes:
// One time op to create the index
// Yes, this syntax is a bit clunky in C# for now
graphClient.Cypher
.Create("INDEX ON :User(Id)")
.ExecuteWithoutResults();
// Find an existing user, create a new one, relate them,
// and index them, all in a single HTTP call
graphClient.Cypher
.Match("(user:User)")
.Where((User user) => user.Id == userId)
.Create("user-[:INVITED]->(user2 {newUser})")
.WithParam("newUser", new User { Id = 4567, Name = "Jim" })
.ExecuteWithoutResults();
More examples here: https://github.com/Readify/Neo4jClient/wiki/cypher-examples
Q3.
"Does this Cypher-based approach mean that we lose POCO-to-node translation for create operations? That was very convenient."
Correct. But that's what we collectively all want to do, where Neo4j is going, and where Neo4jClient is going too.
Think about SQL for a second (something that I assume you are familiar with). Do you run a query to find the internal identifier of a node, including its file offset on disk, then use this internal identifier in a second query to manipulate it? No. You run a single query that does all that in one hit.
Now, a common use case for why people like passing around Node<T> or NodeReference instances is to reduce repetition in queries. This is a legitimate concern, however because the fluent queries in .NET are immutable, we can just construct a base query:
public ICypherFluentQuery FindUserById(long userId)
{
return graphClient.Cypher
.Match("(user:User)")
.Where((User user) => user.Id == userId);
// Nothing has been executed here: we've just built a query object
}
Then use it like so:
public void DeleteUser(long userId)
{
FindUserById(userId)
.Delete("user")
.ExecuteWithoutResults();
}
Or, add even more Cypher logic to delete all the relationships too:
Then use it like so:
public void DeleteUser(long userId)
{
FindUserById(userId)
.Match("user-[:?rel]-()")
.Delete("rel, user")
.ExecuteWithoutResults();
}
This way, you can effectively reuse references, but without ever having to pull them back across the wire in the first place.

Update relationship / payload with the Neo4jClient

I am new to Neo4j and Neo4jClient. I am trying to update an existing relationship. Here is how I created the relationship.
var item2RefAddedBefore = _graphClient.CreateRelationship((NodeReference<Item>)item2Ref,
new AddedBefore(item1Ref, new Payload() { Frequency = 1 }));
For this particular use case, I would like to update the Payload whenever the Nodes and relationship already exist. I am using Cypher mostly with the Neo4jClient.
Appreciate any help!
Use this IGraphClient signature:
void Update<TRelationshipData>(RelationshipReference<TRelationshipData> relationshipReference, Action<TRelationshipData> updateCallback)
where TRelationshipData : class, new();
Like this:
graphClient.Update(
(RelationshipReference<Payload>)item2RefAddedBefore,
p => { p.Foo = "Bar"; });
Update: The syntax is a little awkward right now, where CreateRelationship only returns a RelationshipReference instead of a RelationshipReference<TData> but Update requires the latter, so you need to explicitly cast it. To be honest, we probably won't fix this any time soon as all of the investment for both Neo4j and Neo4jClient is going towards doing mutations via Cypher instead.

DL Query to get the Individual has object relation with given individual - not some (OWL)

Please explain how to get the set of individuals that has a relation ship the given set of individuals along some object property in DL query (not using the some quantifier)
Maybe something like this:
object_property some ({ Individual1 } or ... or { IndividualN })
(Your question is hard to understand, so I'm guessing here.)

Resources