i'm trying to convert a query from cypher to use neo4jclient api in c#
Here is my cypher
start server=node:node_auto_index(serverId='SHO2K3MS49')
MATCH
server-[:IS_SERVER_TYPE]->type,
appEnv-[:HAS_SERVER]->server,
app-[:HAS_ENV]->appEnv
return
server.serverId,
collect([
appEnv.environmentTypeId,
appEnv.appEnvId,
app.appId,
app.appName
]) ;
The query returns one line per server and collects all the applications on that server.
The .CollectAs api as far as i can see only allows single values.
An idea how to do this with the .net api?
EDIT
i've just tried this query
_connectedClient
.Cypher
.Start(new {server = Node.ByIndexLookup("node_auto_index", "serverId", "SHO2K3MS49") })
.Match("server-[:IS_SERVER_TYPE]->type", "appEnv-[:HAS_SERVER]->server", "app-[:HAS_ENV]->appEnv")
.Return((server, appEnv, app) =>
new
{
ServerName = Return.As<string>("server.serverId"),
aa = Return.As<dynamic> ("collect([appEnv.environmentTypeId,appEnv.appEnvId,app.appId,app.appName])")
})
.Results;
and received this result.
stacktrace
at Neo4jClient.Serialization.CypherJsonDeserializer`1.Deserialize(String content)
at Neo4jClient.GraphClient.<>c__DisplayClass1e`1.<Neo4jClient.IRawGraphClient.ExecuteGetCypherResultsAsync>b__1d(Task`1 responseTask)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
innerexception
Accessed JArray values with invalid key value: "data". Array position index expected
message -- removed boilerplate text for brevity
Neo4jClient encountered an exception while deserializing the response from the server. This is likely a bug in Neo4jClient.
Include the full type definition of <>f__AnonymousType1`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].
Include this raw JSON, with any sensitive values replaced with non-sensitive equivalents:
{"columns":["ServerName","aa"],"data":[["SHO2K3MS49",[["PRD","MATT.PRD","MATT","MATT"],["PRD","ARCSERV.PRD","ARCSERV","ArcServ"],["PRD","ACTIVE DIRECTORY _WINDOWS SERVER NETWORKING_.PRD","ACTIVE DIRECTORY _WINDOWS SERVER NETWORKING_","Active Directory (Windows Server networking)"]]]]}
Parameter name: content
It's because the results you bring back from the collect
statement are basically strings with no defining columns. JSON.NET can't infer what the columns are (and you can't use AS
to help it), so all you get are strings like:
"[\r\n"EnvType1",\r\n"AppEnvId1",\r\n"App2",\r\n"App 2"\r\n]"
Which you can get by using the following query:
_connectedClient
.Cypher
.Start(new {server = Node.ByIndexLookup("node_auto_index", "serverId", "SHO2K3MS49") })
.Match("server-[:IS_SERVER_TYPE]->type", "appEnv-[:HAS_SERVER]->server", "app-[:HAS_ENV]->appEnv")
.Return((server, appEnv, app) =>
new
{
ServerName = Return.As<string>("server.serverId"),
aa = Return.As<IEnumerable<string>>("collect([appEnv.environmentTypeId,appEnv.appEnvId,app.appId,app.appName])")
})
.Results;
I've changed the return type for the aa
property to be IEnumerable<string>
.
Another route would be to use GroupBy
after getting the data:
var query2 = GraphClient
.Cypher
.Start(new { server = new NodeReference(1) })
.Match("server-[:IS_SERVER_TYPE]->type", "appEnv-[:HAS_SERVER]->server", "app-[:HAS_ENV]->appEnv")
.Return((server, appEnv, app) =>
new
{
ServerId = Return.As<string>("server.ServerId"),
EnvironmentTypeId = Return.As<string>("appEnv.EnvironmentTypeId"),
AppEnvId = Return.As<string>("appEnv.AppEnvId"),
AppId = Return.As<string>("app.AppId"),
AppName = Return.As<string>("app.AppName"),
});
var results2 = query2.Results.GroupBy(g => g.ServerId).ToList();
Which I think would give you the results in the way you want them, I guess at issue here is whether it's more performant to do the collect
on the server, or to GroupBy
on the client...