[英]How do I retrieve a specific neo4j node property using neo4jclient?
[英]How do I return a Neo4j path with Neo4jClient in .NET?
我正在尝试使用 .NET 中的 Neo4jClient package 从 Neo4j 获取path
。 我想知道如何反序列化它,同时保持table
响应中的强大值,但我似乎只能访问text
响应。
免责声明- 我已经看到了这个答案,但它已经超过 7 年了,几乎不再相关——更不用说最终结果看起来令人难以置信的复杂。
我有一个 Neo4j 数据库,其中包含三种类型的节点。 为了这个问题,我将把它们简化为一个公司示例,因此我们将节点标签称为Employee
、 Department
和Project
。 这些节点通过以下方式互连:
Employee
都与Department
有EMPLOYED_BY
关系。Project
与Department
都有OWNED_BY
关系。Employee
可以与Project
具有WORKS_ON
关系。为了这个问题,这个样本数据提供了数据结构的基线演示。
(:Employee {name:"Sarah Bradshaw"})
-[:EMPLOYED_BY {startDate:"2020-01-01"}]->
(:Department {name:"Finance"})
<-[:OWNED_BY {startDate:"2020-01-01"}]-
(:Project {name:"Quarterly Earnings"})
<-[:WORKS_ON {startDate:"2020-06-01"}]-
(:Employee {name:"Thomas Mitchell"})
-[:EMPLOYED_BY {startDate:"2019-01-01"}]->
(:Department {name:"Administration"})
这是我尝试使用 Neo4jClient package 在 .NET 中复制的查询。
MATCH (from:Employee {name:"Sarah Bradshaw"})
MATCH (to:Employee {name:"Thomas Mitchell"})
CALL apoc.algo.dijkstra(from, to, '', 'd')
YIELD path
RETURN path
表响应
{
"start": {
"identity": 0,
"labels": [ "Employee" ],
"properties": {
"name": "Sarah Bradshaw"
}
},
"end": {
"identity": 3,
"labels": [ "Employee" ],
"properties": {
"name": "Thomas Mitchell"
}
},
"segments": [
{
"start": {
"identity": 0,
"labels": [ "Employee" ],
"properties": {
"name": "Sarah Bradshaw"
}
},
"relationship": {
"identity": 0,
"start": 0,
"end": 1,
"type": "EMPLOYED_BY",
"properties": {
"startDate": "2020-01-01"
}
},
"end": {
"identity": 1,
"labels": [ "Department" ],
"properties": {
"name": "Finance"
}
}
},
{
"start": {
"identity": 1,
"labels": [ "Department" ],
"properties": {
"name": "Finance"
}
},
"relationship": {
"identity": 1,
"start": 2,
"end": 1,
"type": "OWNED_BY",
"properties": {
"startDate": "2020-01-01"
}
},
"end": {
"identity": 2,
"labels": [ "Project" ],
"properties": {
"name": "Quarterly Earnings"
}
}
},
{
"start": {
"identity": 2,
"labels": [ "Project" ],
"properties": {
"name": "Quarterly Earnings"
}
},
"relationship": {
"identity": 2,
"start": 3,
"end": 2,
"type": "WORKS_ON",
"properties": {
"startDate": "2020-06-01"
}
},
"end": {
"identity": 3,
"labels": [ "Employee" ],
"properties": {
"name": "Thomas Mitchell"
}
}
}
],
"length": 3.0
}
文本回复
[
{"name":"Sarah Bradshaw"},
{"startDate":"2020-01-01"},
{"name":"Finance"},
{"name":"Finance"},
{"startDate":"2020-01-01"},
{"name":"Quarterly Earnings"},
{"name":"Quarterly Earnings"},
{"startDate":"2020-06-01"},
{"name":"Thomas Mitchell"}
]
如您所见, text
响应基本上是无用的。 不幸的是,这似乎是我能够通过 Neo4jClient 检索的唯一响应值。
这是基于上述查询的派生 Neo4jClient 语法。 因为我只能获取text
响应,所以我将其反序列化为DataNode
类型的List
——一个简单的 model,它反映了节点的结构及其关系。
client.Cypher
.Match("(from:Employee {name:\"Sarah Bradshaw\"})")
.Match("(to:Employee {name:\"Thomas Mitchell\"})")
.Call("apoc.algo.dijkstra(from, to, '', 'd')")
.Yield("path")
.Return<List<DataNode>>("path")
.ResultsAsync
.Result;
虽然这确实让我有所收获,但问题是在text
响应中没有返回任何使路径相关的东西。 我有一组节点和关系,但我不知道它们是如何互连的。 table
响应列出了开始节点和结束节点,这就是我关心的信息。 我有什么办法可以查询table
响应而不是text
响应?
好的,我假设您正在使用BoltGraphClient
- 与GraphClient
一样,您几乎被卡住了,因为 REST 端点没有给出您所追求的 ID。
Neo4jClient 中有一个名为PathsResultBolt
的Neo4jClient
-但它给出System.Object
作为查询结果中每个属性的答案 - 这不太有用,所以你应该试试这个 ZA2F2ED4FDC4EBC2CBB4ZC21:
public class PathsResultBolt<TNode, TRel>
{
public PathsResultBolt()
{
Nodes = new List<PathsResultBoltNode<TNode>>();
Relationships = new List<PathsResultBoltRelationship<TRel>>();
}
internal PathsResultBolt(IPath path)
{
Start = new PathsResultBoltNode<TNode>(path.Start);
End = new PathsResultBoltNode<TNode>(path.End);
Relationships = path.Relationships.Select(r => new PathsResultBoltRelationship<TRel>(r)).ToList();
Nodes = path.Nodes.Select(r => new PathsResultBoltNode<TNode>(r)).ToList();
}
[JsonProperty("Start")]
public PathsResultBoltNode<TNode> Start { get; set; }
[JsonProperty("End")]
public PathsResultBoltNode<TNode> End { get; set; }
[JsonIgnore]
public int Length => Relationships.Count();
[JsonProperty("Nodes")]
public List<PathsResultBoltNode<TNode>> Nodes { get; set; }
[JsonProperty("Relationships")]
public List<PathsResultBoltRelationship<TRel>> Relationships { get; set; }
public class PathsResultBoltRelationship<T>
{
public long Id { get; set; }
public string Type { get; set; }
public long StartNodeId { get; set; }
public long EndNodeId { get; set; }
public object this[string key] => Properties[key];
public Dictionary<string, T> Properties { get; set; }
public PathsResultBoltRelationship() { Properties = new Dictionary<string, T>(); }
public PathsResultBoltRelationship(IRelationship relationship)
{
Id = relationship.Id;
StartNodeId = relationship.StartNodeId;
EndNodeId = relationship.EndNodeId;
Type = relationship.Type;
Properties = relationship.Properties.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.As<T>());
}
public bool Equals(PathsResultBoltRelationship<T> other)
{
if (other == null)
return false;
return Id == other.Id
&& StartNodeId == other.StartNodeId
&& EndNodeId == other.EndNodeId
&& Type == other.Type
&& Properties.ContentsEqual(other.Properties);
}
public override bool Equals(object obj)
{
return Equals(obj as PathsResultBoltRelationship<T>);
}
public override int GetHashCode()
{
var hashCode = 2105322407;
hashCode = hashCode * -1521134295 + Id.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Type);
hashCode = hashCode * -1521134295 + StartNodeId.GetHashCode();
hashCode = hashCode * -1521134295 + EndNodeId.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<IReadOnlyDictionary<string, T>>.Default.GetHashCode(Properties);
return hashCode;
}
}
public class PathsResultBoltNode<T>
{
public long Id { get; set; }
public List<string> Labels { get; set; }
public object this[string key] => Properties[key];
public Dictionary<string, T> Properties { get; set; }
public PathsResultBoltNode() { Properties = new Dictionary<string, T>(); }
internal PathsResultBoltNode(INode node)
{
Id = node.Id;
Labels = node.Labels?.ToList();
Properties = node.Properties.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.As<T>());
}
public bool Equals(PathsResultBoltNode<T> other)
{
if (other == null)
return false;
return Id == other.Id
&& Labels.ContentsEqual(other.Labels)
&& Properties.ContentsEqual(other.Properties);
}
public override bool Equals(object obj)
{
return Equals(obj as PathsResultBoltNode<T>);
}
public override int GetHashCode()
{
var hashCode = 1343812023;
hashCode = hashCode * -1521134295 + Id.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<IReadOnlyList<string>>.Default.GetHashCode(Labels);
hashCode = hashCode * -1521134295 + EqualityComparer<IReadOnlyDictionary<string, T>>.Default.GetHashCode(Properties);
return hashCode;
}
}
}
你会这样使用:
client.Cypher
.Match("(from:Employee {name:\"Sarah Bradshaw\"})")
.Match("(to:Employee {name:\"Thomas Mitchell\"})")
.Call("apoc.algo.dijkstra(from, to, '', 'd')")
.Yield("path")
.Return<PathsResultBolt<string, string>>("path")
.ResultsAsync
.Result;
你问这个<string, string>
是什么? 第一个是节点的属性类型,第二个是关系。
现在。 这有点垃圾 - 这取决于我不确定如何让实际的 object 值成为有效的正确objects
。 所以最好的方法(!!)是目前对 node 和 rels 都使用string
。 在我使用标准电影数据库的测试中,我得到了这个:
born
属性是一个string
,但这是基本级别,使用int
会导致错误,因为name
不是int。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.