Neo4j:在查询中合并三个节点中的一个重复节点

3
作为我在另一篇帖子中所述,我正在从SQL Server 迁移到 Neo4j,因此我正在应对学习曲线。 我一直在 StackOverflow 和 Google 上搜索并回答我的问题,但是我遇到了一个奇怪的查询结果,这个结果看起来很不可思议。
C# 代码:
public void AddMarketInfo(MarketInfo mi)
{
    Bid bid = mi.Bid;
    Ask ask = mi.Ask;

    var query = clientConnection.Cypher
        .Merge("(newbid:Bid { ID: {bID} })")
        .OnCreate()
        .Set("newbid = {bid}")
            .WithParams(new
            {
                bID = bid.ID,
                bid
            })
        .Merge("(newask:Ask { ID: {aID} })")
        .OnCreate()
        .Set("newask = {ask}")
            .WithParams(new
            {
                aID = ask.ID,
                ask
            })
        .Merge("(newMarketInfo:MarketInfo { ID: {id}, ASK: {askID}, BID: {bidID} })")
        .OnCreate()
        .Set("newMarketInfo = {mi}")
            .WithParams(new
            {
                id = mi.ID,
                bidID = bid.ID,
                askID = ask.ID,
                mi
            })
    .CreateUnique("(newask)-[rA:Ask_Input_Data]->(newMarketInfo)")
    .CreateUnique("(newbid)-[rB:Bid_Input_Data]->(newMarketInfo)");
    query.ExecuteWithoutResults();
}

我目前正在调试程序,因此该语句正在同一数据上执行多次。是的,我现在要进入数据库并删除所有节点。

当创建“Bid”节点和“Ask”节点时,它成功地与现有节点合并,但“MarketInfo”节点被复制了。

你有什么想法吗?

enter image description here

enter image description here

编辑2:修改查询

所以我在阅读neo4j文档:

https://neo4j.com/docs/developer-manual/current/cypher/clauses/merge/#query-merge-on-create-on-match

他们提供的例子是:

使用ON CREATE和ON MATCH合并节点并设置属性,如果需要创建节点则进行操作。

查询。

MERGE (keanu:Person { name: 'Keanu Reeves' })
ON CREATE SET keanu.created = timestamp()
ON MATCH SET keanu.lastSeen = timestamp()
RETURN keanu.name, keanu.created, keanu.lastSeen

查询创建了一个名为'keanu'的节点,并在创建时设置了时间戳。如果'keanu'已经存在,则会设置不同的属性。
因此,我修改了我的代码以“执行相同的操作”:
var query = graphClient.Cypher
            .Merge("(newbid:Bid { ID: {bID} })")
            .OnMatch()
            .Set("newbid = {bid}")
            .OnCreate()
            .Set("newbid = {bid}")
                .WithParams(new
                {
                    bID = bid.ID,
                    bid
                })

            .Merge("(newask:Ask { ID: {aID} })")
            .OnMatch()
            .Set("newask = {ask}")
            .OnCreate()
            .Set("newask = {ask}")
                .WithParams(new
                {
                    aID = ask.ID,
                    ask
                })

            .Merge("(newMarketInfo:MarketInfo { ID: {id}, ASK: {askID}, BID: {bidID} })")
            .OnCreate()
            .Set("newMarketInfo = {mi}")
                .WithParams(new
                {
                    id = mi.ID,
                    bidID = bid.ID,
                    askID = ask.ID,
                    mi
                })
            .Merge("(newask)-[rA:Ask_Input_Data]->(newMarketInfo)")
            .Merge("(newbid)-[rB:Bid_Input_Data]->(newMarketInfo)");
        query.ExecuteWithoutResultsAsync();

然而,MarketInfo节点仍在被复制。我认为现在我走在了正确的道路上,但是......还有一些东西我没有理解。


Jeremy,抱歉,我犯了一个错误并删除了我的先前评论。 - Bruno Peres
确认一下:所有的属性 mi.IDbid.IDask.ID 在所有执行中都是相同的,对吗? - Bruno Peres
@JeremyParker 我不确定我理解的是否正确。你是在说,如果你的代码两次合并 (:MarketInfo { ID: 1, ASK: 2, BID: 3})(具有相同的三个属性值),那么每次都会创建一个新节点(这是不应该发生的)吗?还是你是在说每次这三个值都有所变化(这应该导致每次都创建一个新节点)? - cybersam
@cybersam 我的意思是,对X数据集运行上述代码将创建一个MarketInfo节点、一个Bid节点和一个Ask节点。Ask和Bid将与MarketInfo节点相关联。如果我重新运行完全相同的数据,将会有两个MarketInfo节点、一个Bid节点和一个Ask节点...其中Ask和Bid节点将与两个MarketInfo节点相关联。 - Jeremy Parker
1
请展示一个导致此行为的 mi 对象。 - cybersam
显示剩余4条评论
2个回答

2

所以问题在这里,这让我很烦恼...

你不能将“ID”用作对象的参数。你可以使用“Id”或“id”或“iD”,但不能使用“ID”。一旦我改用“Id”,节点就不会再被复制了。


0
  1. 根据提供的信息,看起来 "(newMarketInfo:MarketInfo { ID: {id}, ASK: {askID}, BID: {bidID} })" 每次运行代码时都有不同的 ID 值。

  2. 另一个可能性是 mi 参数值具有会更改节点的 { ID: {id}, ASK: {askID}, BID: {bidID} } 值的值。换句话说/例如,您可能正在合并 { ID: {1}, ASK: {2}, BID: {3} },然后在 ON CREATE 中立即设置 "newMarketInfo = {mi}",这将更改节点的值为 { ID: {2}, ASK: {3}, BID: {4}, exampleValue: {5} }。在这种情况下,合并将始终创建一个新节点,但当您检查结果时,创建的节点将看起来相同。明白了吗?

更新

你添加的照片显示你的MarketInfo节点没有ASKBID属性(你正在合并的属性)。假设这些属性不应该是null。这让我想到了上面提到的第二个假设来解释发生了什么。为了测试这个假设,你可以尝试消除


.OnCreate().Set("newMarketInfo = {mi}")

你的查询中的一部分。在这种情况下,查看合并后在数据库中持久化的节点。该节点是否具有ASK / BID属性?如果是,则找到了问题所在。您还可以查看在此场景中运行查询两次是否会添加第二个节点。如果没有,则问题肯定是ON CREATE子句。


此外,可能与此无关,但显然我不知道您为什么要向MarketInfo节点添加askIDbidID属性(也许您确实希望在提取MarketInfo节点时始终向客户端返回这些ID),但看起来您正在为查询目的添加外键到该节点。如果是这种情况,您很可能应该消除这些属性并用关系替换它们,除非您已经拥有所需的关系(newask)-[rA:Ask_Input_Data]->(newMarketInfo),那么您可以直接消除这些属性。 - John
我添加了一张暴露数据的照片,希望有人能看到我没有发现的东西。 - Jeremy Parker
关于第二个评论,我正在将子节点ID添加到父节点中,以备将来查询。有时,我不会返回子节点,但我将需要在未来的函数中查询子节点。我觉得这种方法可以在未来提供最大的灵活性,同时也可以通过节点建立纸质记录,以验证我们正在做我们所说的事情,以满足监管机构和客户的要求。 - Jeremy Parker
@JeremyParker 我根据照片更新了我的答案。我怀疑我的第二个假设解释了你的代码中发生的事情。关于在cypher中使用子节点ID进行查询(又称关系数据库外键),您可以执行MATCH(marketInfo:MarketInfo {ID:$marketInfoID}) <- [: Ask_Input_Data] -({ID:$askId})返回marketInfo。话虽如此,如果您添加一个复合索引ON:MarketInfo(ID,ASK,BID),则您当前的方法可能比这种方法更有效率。无论如何,我只是想指出关系的力量。 - John
我更新了我的查询,以为它与neo4j在他们的文档中展示的查询相匹配...但仍然有些不对劲。你有什么想法吗? - Jeremy Parker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接