Returning multiple columns in Neo4jClient Cypher Query - neo4jclient

I am using Azure and finding the performance to be slow. In order to reduce the round trip time, I am clubbing the following queries into one query.
var queryItem = _graphClient
.Cypher
.Start(new
{
n = Node.ByIndexLookup("item_idx", "SKU", sSKU1),
})
.Return<Node<Item>>("n");
somewhere else in the code I have following statements
var queryItem = _graphClient
.Cypher
.Start(new
{
m = Node.ByIndexLookup("item_idx", "SKU", sSKU2),
})
.Return<Node<Item>>("m");
I tried to combine above two queries into a single query like this
var queryItem = _graphClient
.Cypher
.Start(new
{
n = Node.ByIndexLookup("item_idx", "SKU", sSKU1),
m = Node.ByIndexLookup("item_idx", "SKU", sSKU2),
})
.Return<Node<Item>>("n");
I know above is only for single column so I tried using following return statement
.Return((n, m) => new
{
N = n.CollectAs<Node<Item>>(),
M = m.CollectAs<Node<Item>>()
});
but then I have problems with the following statement
Node<Item> item1 = itemQueryResult.First();
It says Error Cannot implicitly convert type 'AnonymousType#1' to 'Neo4jClient.Node.
Can you please suggest a simple syntax or returning multiple columns and a way to extract the first node? TIA.

I think what you're missing here is that the Return statement returns one object per Cypher row.
Your query is returning a table like this:
|-----------------|
| n | m |
|-----------------|
| Node | Node |
|------------------
That's one table, with one row, with two columns.
In this statement, you are returning an anonymous type per Cypher row:
.Return((n, m) => new
{
N = n.CollectAs<Node<Item>>(),
M = m.CollectAs<Node<Item>>()
});
The return type of that method is IEnumerable<AnonymousType>.
You're then trying to get the first row (an anonymous type) and implicitly cast that to Node<Item>, which is not valid.
You should get the row, then get the properties within it.
Some other things to note:
You don't want to use CollectAs in this scenario: that will turn each cell of your table into an array with a single value, which just adds more indirection.
.As<Node<T>>() can be written as .Node<T>()
With that in mind, here's the query you want:
var result = _graphClient
.Cypher
.Start(new
{
n = Node.ByIndexLookup("item_idx", "SKU", sSKU1),
m = Node.ByIndexLookup("item_idx", "SKU", sSKU2),
})
.Return((n, m) => new
{
N = n.Node<Item>(),
M = m.Node<Item>()
})
.Results
.Single();
var n = result.N;
var m = result.M;
Make sense?
PS: I hope you aren't actually clubbing anything. Baby seals don't like that. You are combining queries.

Related

How to set enumeration on properties for selected nodes in one cypher statement?

My graph contains a set of nodes which are enumerated using a dedicated field fid. I want to update this enumeration periodically.
My current approach is to reset the enumeration and execute multiple statements that increase the fid for each node.
1. (f:File) set f.fid = -1
for(int i = 0; i < count ; i++) {
2. (f:File) set f.fid = i where id(f) = nodeId
}
I guess it should be possible to execute this task using a single cypher statement using the foreach clause.
MATCH p=(f:File)
FOREACH (n IN nodes(p)| SET f.fid = -1 )
I was looking for something similar to this statement.
MATCH (f:File)
WITH COLLECT(f) AS fs
WITH fs, i = 0
FOREACH (f in fs, i=i+1| SET f.fid = i ) return f.fid, f.name
Based on the following console set : http://console.neo4j.org/r/447qni
The following query seems to do the trick :
MATCH (f:File)
WITH collect(f) as f, count(f) AS c
UNWIND range(0,c-1) AS x
WITH f[x] AS file,x
SET file.iteration = x+1

neo4jclient ill formed cypher request sent to server

Trying to execute the following cypher query (which executes ok from neoclipse)
START a=node(*) MATCH a-[:Knows]->p WHERE (p.Firstname! = "Steve" ) RETURN p
from neo4jclient with the following statement
protected void Populate()
{
var client = new GraphClient(new Uri("http://altdev:7474/db/data"));
client.Connect();
var query = client.Cypher
.Start(new RawCypherStartBit("all", "node(*)"))
.Match("all-[:Knows]->p")
.Where((Person p) => p.Firstname == "Steve")
.Return<Node<Person>>("Person");
var people = query.Results;
}
the client throws an exception, as follows
The query was: START all=node(*)
MATCH all-[:Knows]->p
WHERE (p.Firstname! = {p0})
RETURN Person
The response status was: 400 Bad Request
The response from Neo4j (which might include useful detail!) was: {
"message" : "Unknown identifier `Person`.",
"exception" : "SyntaxException",
"fullname" : "org.neo4j.cypher.SyntaxException",
"stacktrace" : [ "org.neo4j.cypher.internal.symbols.SymbolTable.evaluateType(SymbolTable.scala:59)", "org.neo4j.cypher.internal.commands.expressions.Identifier.evaluateType(Identifier.scala:47)", "org.neo4j.cypher.internal.commands.expressions.Expression.throwIfSymbolsMissing(Expression.scala:52)", "org.neo4j.cypher.internal.pipes.ColumnFilterPipe$$anonfun$throwIfSymbolsMissing$1.apply(ColumnFilterPipe.scala:61)", "org.neo4j.cypher.internal.pipes.ColumnFilterPipe$$anonfun$throwIfSymbolsMissing$1.apply(ColumnFilterPipe.scala:61)", "scala.collection.immutable.List.foreach(List.scala:309)", "org.neo4j.cypher.internal.pipes.ColumnFilterPipe.throwIfSymbolsMissing(ColumnFilterPipe.scala:61)", "org.neo4j.cypher.internal.pipes.PipeWithSource.<init>(Pipe.scala:63)", "org.neo4j.cypher.internal.pipes.ColumnFilterPipe.<init>(ColumnFilterPipe.scala:30)", "org.neo4j.cypher.internal.executionplan.builders.ColumnFilterBuilder.handleReturnClause(ColumnFilterBuilder.scala:60)", "org.neo4j.cypher.internal.executionplan.builders.ColumnFilterBuilder.apply(ColumnFilterBuilder.scala:38)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanImpl.prepareExecutionPlan(ExecutionPlanImpl.scala:54)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanImpl.<init>(ExecutionPlanImpl.scala:36)", "org.neo4j.cypher.ExecutionEngine$$anonfun$prepare$1.apply(ExecutionEngine.scala:80)", "org.neo4j.cypher.ExecutionEngine$$anonfun$prepare$1.apply(ExecutionEngine.scala:80)", "org.neo4j.cypher.internal.LRUCache.getOrElseUpdate(LRUCache.scala:37)", "org.neo4j.cypher.ExecutionEngine.prepare(ExecutionEngine.scala:80)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:72)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:76)", "org.neo4j.cypher.javacompat.ExecutionEngine.execute(ExecutionEngine.java:79)", "org.neo4j.server.rest.web.CypherService.cypher(CypherService.java:94)", "java.lang.reflect.Method.invoke(Method.java:616)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)" ]
}
As you can see, essentially the queries are the same. And the nodes I'm trying to get are of _type "Person"
TIA
Marcelo
In your MATCH clause you use the identity p:
.Match("all-[:Knows]->p") // becomes MATCH all-[:Knows]->p
In your RETURN clause you change to using the identity Person:
.Return<Node<Person>>("Person"); // becomes RETURN person
You need to pick one and be consistent.
Integrating some other clean up too, your full query should be:
var query = client.Cypher
.Start(new { all = All.Nodes })
.Match("all-[:Knows]->p")
.Where((Person p) => p.Firstname == "Steve")
.Return<Person>("p");
It's down to the way you are creating the Cypher code, specifically what you are returning:
var query = client.Cypher
.Start(new RawCypherStartBit("all", "node(*)"))
.Match("all-[:Knows]->p")
.Where((Person p) => p.Firstname == "Steve")
.Return<Node<Person>>("p"); // <-- THIS LINE SHOULD SAY 'P' NOT 'Person'
The return statement requires the name to be the same as the node you have defined. So you use: all-[:knows]->p where you define p. Now you need to return it.
(Which is what Peter is saying in his answer :))
You are trying to return a Person node that is not assigned to anything in the query.

Returning property and count columns together in Neo4jClient Cypher Query

I have a Cypher query likes this:
START n=node:permit_idx(PmtID= "111")
Match n-[:Assinged]->m<-[:Assinged]-p
RETURN p.PmtID, count(m);
I got error when I try to do it using Neo4jClient Cypher Query
var results = graphClient
.Cypher
.Start(new { n = Node.ByIndexLookup("permit_idx", "PmtID", "111") })
.Match("Match n-[:Assigned]->m<-[:Assigned]-p")
.Return((m, p) => new
{
PDPmtID = "p.PmtID",
MCount = "count(m)"
})
.Results;
If only need to return one property or one count, we can use
.Return<int>("count(m)");
But how to return property and count together?
.Return((m, p) => new
{
PDPmtID = Return.As<int>("p.PmtID"),
MCount = m.Count()
})
Or, preferred right now:
.Return((m, p) => new
{
Permit = p.As<Permit>(),
MCount = m.Count()
})
You need to use the custom text option in your compound Return clause:
.Return((m, p) => new
{
PDPmtID = Return.As<int>("p.PmtID"),
MCount = Return.As<int>("count(m)")
})
(This is based on the documentation for the Neo4jClient)

dynamically creating a query in Neo4jClient

I am trying to create a dynamic Cypher query with Neo4jClient. My code is turning very redundant because of .Start in Neo4jClient. In .Start, I would like to get nodes from an index. The nodes can be variable from 1 to 10. So I have to create a switch statement, which is getting really long.
.Start(new
{
n = Node.ByIndexLookup("name_idx", "Name", sNameArray[0]),
})
For two nodes, it is
.Start(new
{
n = Node.ByIndexLookup("name_idx", "Name", sNameArray[0]),
m = Node.ByIndexLookup("name_idx", "Name", sNameArray[1]),
})
And so forth
.Match and .With are dynamically generated using string operations, so no issues there. .Return has only limited return value, so no issues there either.
My main concern is because of .Start, I have to repeat the full .Cypher statement. If I can get around it, I will have nice clean code. Any suggestions?
You can use a Dictionary so for example your second version could be:
.Start(new Dictionary<string, object>{
{"n", Node.ByIndexLookup("name_idx", "Name", sNameArray[0])},
{"m", Node.ByIndexLookup("name_idx", "Name", sNameArray[1])},
}
Which would allow you to do something like:
var start = new Dictionary<string, object>();
for(int i = 0; i < sNameArray.Length; i++)
{
start.Add("n" + i, Node.ByIndexLookup("name_idx", "Name", sNameArray[i]));
}
graphClient.Cypher.Start(start).Where( /**** ETC ****/ );

How do I get list of nodes from calculated shortest path?

My Cypher looks like this:
START source=node(16822), target=node(12449)
MATCH p = allShortestPaths(source-[*]-target)
return p
And I want to write equivalent C# code for this. This is what I've come up till now
var query = client.Cypher
.Start(new { source = sourceNode.Reference, target = targetNode.Reference })
.Match("p = allShortestPaths(source-[*]-target)")
.Return<Node<Data>>("x");
Where Data is the class which has a string property(string ID).
What should i put in place of x to get my result as a list of concatenated IDs which comprises the path.
Cypher 2.0
START source=node(16822), target=node(12449)
MATCH p = allShortestPaths(source-[*]-target)
return nodes(p)
Good old way of executing query was the last resort which i used
CypherQuery query1 = new CypherQuery(#"START m=node(" + sourceNode.Reference.Id.ToString() + "), n=node(" + targetNode.Reference.Id.ToString() + #")
match p = allshortestpaths(m-[*]-n)
return distinct Extract(x in NODES(p): x.NodeId) as paths", paramCollection, CypherResultMode.Set);
var paths = ((IRawGraphClient)client).ExecuteGetCypherResults<List<string>>(query1);

Resources