After calling neo4j with neocons (cy/tquery conn node-query {:_nodeid _nodeid}), how do you perform accessing functions to get property values from the keys that are returned from the neo4j datastore response?
For example if this object was the response from the neo4j datastore, what neocons syntax do I use to access the value stored in key "attributes"?
[ {
"id": "letter-a",
"name": "Letter A",
"attributes": [ ... ]
}]
Currently I can only get so far as (first _response) but (get-in (first _response) [:attributes]) is giving me back nil
******************* EDIT *******************************
Here is the cypher query string I use as an argument to invoke the tquery function:
(def node-query "MATCH (n)-[attributelist:RELATIONSHIPTYPE]->(target)
RETURN n.id AS id,
n.name AS name,
COLLECT({
target : target.id
}) AS attributes;")
I don't understand what type of variable tquery returns? It looks like this object when the client displays it all the way in the browser:
[
{
"id": "node-999990a0a0a0sa0",
"name": "Node Name",
"attributes": [
{
"target": "node-id-one"
},
{
"target": "node-id-two"
},
{
"target": "node-id-two"
},
{
"target": "node-id-two"
},
{
"target": "node-id-three"
}
]
}
]
But I want to intercept what is returned from the tquery before the clojure server delivers it to the client and I want to manipulate the array value of the key "attributes" so I can run a reduce (tally) report before I deliver a rebuilt object response to the client.
{
...
"attributes" : {
"node-id-one" : 1,
"node-id-two" : 3,
"node-id-three" : 1
}
}
But I am having trouble because I do not know the syntax to access the "attributes" key from the object that is returned from the tquery
Sorry I don't understand your question. Which query did you run with tquery?
Usually you return the data you're interested in directly from the query.
e.g
MATCH (p:Person)-[:ACTED_IN]->(m)
WHERE p.name = "Tom Hanks"
RETURN m.title, m.released`
Otherwise you'd have to requery using a label+unique-property
MATCH (m:Movie)
WHERE m.title = "The Matrix"
RETURN m.title, m.released`
or node-id match.
MATCH (m:Movie)
WHERE id(m) = 123
RETURN m.title, m.released`
You usually would use parameters instead of literal values, i.e. {name}, {title}, {id}.
Update
I think for intercepting you would have to look into the neocons implementation.
Note: there is no clojure server, it's a Neo4j server with an http endpoint.
You should be able to do what you want (almost) in cypher.
MATCH (n)-[:RELATIONSHIPTYPE]->(target)
WITH n, target.id as target, count(*) as c
RETURN n.id as id, n.name as name, collect([target,c]) as targets;
Unfortunately right now there are no dynamic map-keys in Cypher, so a tuple-collection will have to do.
PS
You should use a label at least for your n (and optionally target) nodes.
Related
I have two nodes A and B (A->B) connected via two relationships. Those 2 relationships are unique. For example, you can think of the two rels as two paths from A to B at two different times. Converting them to one relationship is not viable at this time.
For displaying in UI, query result should be a tree structure. Used following query to get the tree
MATCH p=(n:Label1 {name:'main'})-[:calls*..2]->(m)
WITH COLLECT(p) AS ps
CALL apoc.convert.toTree(ps) yield value
RETURN value;
the resulting tree is
Preferred result is
How can I get a tree with duplicate children is more than one relationship exists between same two nodes?
Thanks.
I offer a hack on this SO question. Although it is not exactly the resulting nested document as the apoc function but I think it can server your purpose.
MATCH p=(n:Label1 {name:'main'})-[:calls*..2]->(m)
// each path will be returned
WITH COLLECT(p) AS ps, p, n
CALL apoc.convert.toTree(ps) yield value
// return node n and it's relationships as a nested document
RETURN {_id: ID(n), _type: labels(n), node:n, relationships: collect(value['calls'][0])} as result
Sample result:
[
{
"result": {
"_id": 31,
"_type": [
"Label1"
],
"node": {
"name": "main"
},
"relationships": [
{
"calls.y": "prop y",
"_type": "Main",
"_id": 32
},
{
"_type": "Main",
"_id": 32,
"calls.x": "prop x"
}
]
}
}
]
If I query a relationship in my database like below
MATCH (n)-[t]-[n] RETURN t
I get the following output:
{
"identity": 423006861,
"start": 89091471,
"end": 278664,
"type": "RELATION",
"properties": {
"value": 7.0
}
}
How can I access the identity, start, end and type values?
[...] RETURN t.start just gives me null which is clearly not right...
I have the feeling that only the properties part can be accessed. Is this true? What am I doing wrong?
The following functions are available on relationships :
startNode()
endNode()
id()
So,
MATCH (n)-[t]-[n]
RETURN
id(startNode(t)) AS startNodeId,
id(endNode(t)) AS endNodeId,
id(t) AS relationshipId
I have the nodes user and game with some relationships between them.
My REST API should return all relationships between the games and 1 user.
The cypher query i use is:
MATCH (u:User {id: '1234'} ) -[rel]- (game:Game) return game{.*, relationships: collect(DISTINCT rel)}
In my Neo4j Browser, everything works as expected and i see all properties i need.
But the GetMapping retuns everything except the relationship properties.
Neo4j Browser
{
"relationships": [
{
"identity": 54,
"start": 9,
"end": 8,
"type": "OWNED",
"properties": {
"ownedDate": "2021-07-03"
}
},
{
"identity": 45,
"start": 9,
"end": 8,
"type": "PLAYED",
"properties": {
"times": 5
}
}
],
"name": "Blood Rage",
"state": "ACTIVE",
"id": "1c152c91-4044-41f0-9208-0c436d6f6480",
"gameUrl": "https://asmodee.de/blood-rage"
}
GetMapping result (As you can see, the relationships are empty, but i have more empty JsonObjects, when there are more Relationships
{
"game": {
"relationships": [
{},
{}
],
"name": "Blood Rage",
"gameUrl": "https://asmodee.de/blood-rage",
"state": "ACTIVE",
"id": "1c152c91-4044-41f0-9208-0c436d6f6480"
}
}
The GetMapping is:
...
final ReactiveNeo4jClient client;
...
...
...
#GetMapping(value = { "/{id}/games"})
#RolesAllowed({"user", "admin"})
Flux<Map<String, Object>> findGamesByUser(#PathVariable String id){
String query = "MATCH (uuser:User {id: '" + id + "'} ) -[rel]- (game:Game) return game{.*, relationships: collect(DISTINCT rel)}";
return client.query(query).fetch().all();
}
A RelationshipProperty-Example
#RelationshipProperties
#Data
#Builder
public class PlayedGame {
#Id
#GeneratedValue
private Long relationshipId;
#Property
int times = 0;
#TargetNode private GameEntity game;
public int addPlay(){
this.times = this.times + 1;
return this.times;
}
}
What do i have to change in my GetMapping to show the relationship-properties?
Thank you,
Kevin
You need to return the actual nodes and relationships, otherwise you're missing the id-mapping.
There should be examples in the SDN docs.
Best if you have a small reproducible example (e.g. with the default movies graph).
Not sure if there is something off in your SDN setup, in general for such simple queries you should be able to just use a repository and not need to write cypher queries by hand.
The general information given by Michael is correct but there is more in you question:
First of all the meta domain model is completely ignored if you are using the Neo4jClient. It does not automatically map anything back but uses the driver's types.
As a result you will end up with an (current state of this answer) InternalRelationship which does not have any getter-methods.
I assume that you are serializing the result in the application with Jackson. This is the reason why you see objects that represent the relationships but without any content within.
If you want to get things mapped for you, create also the domain objects properly and use (at least) the Neo4jTemplate with your query.
If you model User, Game, and the relationship properties like PlayedGame correctly, a
neo4jTemplate.findAll("MATCH (u:User)<-[rel]-(g:Game) return u, collect(rel), collect(g)", User.class)
will map the results properly. Also if this is all you have, you could also skip the custom query at all and use
neo4jTemplate.findAll(User.class)
or
neo4jTemplate.findById(useId, User.class)
I am using the neo4jrestclient library.
from neo4jrestclient.client import GraphDatabase
from neo4jrestclient import client
from neo4jrestclient import query
gdb = GraphDatabase("http://localhost:7474/db/data/")
q = """MATCH n RETURN n;"""
result = gdb.query(q=q)
print(result[0])
When I am executing the query "MATCH n RETURN n, the output is:
[{
'all_relationships': 'http://localhost:7474/db/data/node/1131/relationships/all',
'all_typed_relationships': 'http://localhost:7474/db/data/node/1131/relationships/all/{-list|&|types}',
'self': 'http://localhost:7474/db/data/node/1131',
'labels': 'http://localhost:7474/db/data/node/1131/labels',
'properties': 'http://localhost:7474/db/data/node/1131/properties',
'create_relationship': 'http://localhost:7474/db/data/node/1131/relationships',
'outgoing_relationships': 'http://localhost:7474/db/data/node/1131/relationships/out',
'data': {
'title': 'title',
'name': 'Poludnie'
},
'incoming_typed_relationships': 'http://localhost:7474/db/data/node/1131/relationships/in/{-list|&|types}',
'property': 'http://localhost:7474/db/data/node/1131/properties/{key}',
'paged_traverse': 'http://localhost:7474/db/data/node/1131/paged/traverse/{returnType}{?pageSize,leaseTime}',
'incoming_relationships': 'http://localhost:7474/db/data/node/1131/relationships/in',
'outgoing_typed_relationships': 'http://localhost:7474/db/data/node/1131/relationships/out/{-list|&|types}',
'traverse': 'http://localhost:7474/db/data/node/1131/traverse/{returnType}'}]
I see that the node’s id = 1131. The question is: can I obtain this id in raw forms without those links? I would like to have only the id together with the value of the ‘data’ field.
In Cypher, that could be expressed like this:
MATCH (n) RETURN {id: ID(n), name: n.name, title: n.title} as city
In the response, the data hash will contain an array and each element's row key will contain this data accessible using their given keys.
To get "just the id and data, change your query to:
MATCH (n) RETURN id(n), n.data
See if that is satisfactory.
I am trying to get a path from a base node to its root node as 1 row. The Cypher query looks like this:
start n = node:node_auto_index(Name = "user1") match path = (n-[r:IS_MEMBER_OF_GROUP*]->b) return last(collect(distinct path));
But when changing this over to the Neo4JClient syntax:
var k = clientConnection.Cypher
.Start(new { n = "node:node_auto_index(Name = 'user1')" })
.Match("path = (n-[r:IS_MEMBER_OF_GROUP*]->b)")
.ReturnDistinct<Node<Principles>>("last(collect(path))").Results;
It gets an error:
{"Value cannot be null.\r\nParameter name: uriString"}
When continuing on from there:
Neo4jClient encountered an exception while deserializing the response from the server. This is likely a bug in Neo4jClient.
Please open an issue at https://bitbucket.org/Readify/neo4jclient/issues/new
To get a reply, and track your issue, ensure you are logged in on BitBucket before submitting.
Include the full text of this exception, including this message, the stack trace, and all of the inner exception details.
Include the full type definition of Neo4jClient.Node`1[[IQS_Neo4j_TestGraph.Nodes.Principles, IQS Neo4j TestGraph, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].
Include this raw JSON, with any sensitive values replaced with non-sensitive equivalents:
{
"columns" : [ "last(collect(path))" ],
"data" : [ [ {
"start" : "http://localhost:7474/db/data/node/3907",
"nodes" : [ "http://localhost:7474/db/data/node/3907", "http://localhost:7474/db/data/node/3906", "http://localhost:7474/db/data/node/3905", "http://localhost:7474/db/data/node/3904" ],
"length" : 3,
"relationships" : [ "http://localhost:7474/db/data/relationship/4761", "http://localhost:7474/db/data/relationship/4762", "http://localhost:7474/db/data/relationship/4763" ],
"end" : "http://localhost:7474/db/data/node/3904"
} ] ]
}
How would one convert the cypher query to Neo4JClient query?
Well, the thing you are returning is a PathsResult not a Node<>, so if you change your query to be:
var k = clientConnection.Cypher
.Start(new { n = "node:node_auto_index(Name = 'user1')" })
.Match("path = (n-[r:IS_MEMBER_OF_GROUP*]->b)")
.ReturnDistinct<PathsResult>("last(collect(path))").Results; //<-- Change here
you will get results, this returns what I get from running your query against my db, if you specifically want the nodes this post: Getting PathsResults covers converting to actual nodes and relationships.
One other thing, (and this will help the query perform better as neo4j can cache the execution plans easier), is that you can change your start to make it use parameters by doing:
.Start(new { n = Node.ByIndexLookup("node_auto_index", "Name", "user1")})