Skip to content

One node has two rels, but only return one rel when query all #2592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
liseri opened this issue Sep 14, 2022 · 12 comments
Closed

One node has two rels, but only return one rel when query all #2592

liseri opened this issue Sep 14, 2022 · 12 comments
Assignees
Labels
status: feedback-provided Feedback has been provided

Comments

@liseri
Copy link

liseri commented Sep 14, 2022

Issue

One node has two rels, but only return one rel when query all.

  • It is normal return, when query one use spring-data-neo4j.
  • It is normal return, when query one use cql in neo4j-browser.
  • It is normal return, when query all use cql in neo4j-browser.
  • ** It is not normal return**, when query all use spring-data-neo4j.

query one Log (It is normal)

the node 20049 has two rels like this RECORD [node<20049>, [relationship<20044>, relationship<20043>], [node<20047>, node<20048>]] as the last line below

...
C: RUN "MATCH (s:hktxjm)
WHERE s.model = 'hktxjmmodel9' and s.idd = 'node-7f532b96-bc60-47d9-a394-ca4b5c97d7d0' AND s.nodeStatu = 'ACTIVE'
optional MATCH (s)-[r]-(t:hktxjm)
WHERE type(r) in ['guanXi']
RETURN s,collect(r), collect(t)
" {} {}
... C: PULL {n=1000}
... S: SUCCESS {t_first=1, fields=["s", "collect(r)", "collect(t)"], qid=0}
... S: RECORD [node<20049>, [relationship<20044>, relationship<20043>], [node<20047>, node<20048>]]
...

query all Log (It is not normal)

the node 20049 has two rels like this RECORD [node<20049>, [relationship<20044>, relationship<20043>], [node<20047>, node<20048>]] as the last line below, **but in return results, only one rel, the outgoingEdges list has only one element **

...
RUN "MATCH (s:hktxjm)
WHERE s.model = $model AND s.nodeStatu = 'ACTIVE' 
WITH s  SKIP $skip LIMIT $limit 
optional MATCH (s)-[r]-(t:hktxjm)
WHERE type(r) in ['guanXi']
RETURN s,collect(r), collect(t)" {0="hktxjmmodel9", limit=100, model="hktxjmmodel9", skip=0} {}
2022-09-14 ... C: PULL {n=1000}
2022-09-14 ... S: SUCCESS {t_first=1, fields=["s", "collect(r)", "collect(t)"], qid=0}
2022-09-14 ... S: RECORD [node<20043>, [relationship<20042>, relationship<20040>, relationship<20041>], [node<20046>, node<20044>, node<20045>]]
2022-09-14 ... S: RECORD [node<20044>, [relationship<20040>], [node<20043>]]
2022-09-14 ... S: RECORD [node<20045>, [relationship<20041>], [node<20043>]]
2022-09-14 ... S: RECORD [node<20046>, [relationship<20042>], [node<20043>]]
2022-09-14 ... S: RECORD [node<20047>, [relationship<20044>], [node<20049>]]
2022-09-14 ... S: RECORD [node<20048>, [relationship<20043>], [node<20049>]]
2022-09-14 ... S: RECORD [node<20049>, [relationship<20044>, relationship<20043>], [node<20047>, node<20048>]]
...

Entity

@Node(primaryLabel="hktxjm")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class TxjmNodeEntity extends TxjmCellEntity {
    @Id
    @GeneratedValue
    Long id;

    @NotNull
    @Size(min = 1, max = 50)
//    @Builder.Default
    private String idd;

    @NotNull
    @Size(min = 1, max = 50)
    private String model;

    @NotNull
    @ReadOnlyProperty
    @Size(min = 1, max = 999)
    private String nodeVersion;

    @NotNull
    private TxjmModel.TxjmCellStatu nodeStatu;

    @NotNull
    @Size(min = 1, max = 50)
    private String shape;

    @NotNull
    @Size(min = 1, max = 50)
    private String appType;

    @NotNull
    @Size(min = 1, max = 50)
    private String defaultName;

    @NotNull
    @Size(min = 1, max = 50)
    private String name;

    @Size(max = 100)
    private String description;

    @CompositeProperty
    // @Singular(ignoreNullCollections = true)
    private Map<String, String> datas;

    // @Singular(ignoreNullCollections = true)
    @JsonManagedReference
    @Relationship(type = "guanXi", direction = Relationship.Direction.OUTGOING)
    private List<TxjmEdgeEntity> outgoingEdges;
    ...

import data

you can use this cql to init data

with [{shape:"hktxjm.liuCheng",appType:"fuWuRW",defaultName:"服务任务",name:"测试服务任务2",description:"测试加的内容",`datas.placeholders`:"1",`datas.parentIdd`:"",`datas.extendField`:"其它1",idd:"node-16d062f1-2b70-11ed-ba00-6c4b907924b0",nodeVersion:"1",model:"hktxjmmodel9",nodeStatu:"ACTIVE"},{shape:"hktxjm.zhanLue",appType:"ceDu",defaultName:"测度",name:"测试测度2",description:"测试",`datas.placeholders`:"1",`datas.parentIdd`:"",idd:"node-16d8098e-2b70-11ed-b3be-6c4b907924b0",nodeVersion:"1",model:"hktxjmmodel9",nodeStatu:"ACTIVE"},{shape:"hktxjm.zhanLue",appType:"quDongL",defaultName:"驱动力",name:"测试驱动力2",description:"测试",`datas.placeholders`:"1",`datas.parentIdd`:"",idd:"node-16d089ef-2b70-11ed-9832-6c4b907924b0",nodeVersion:"1",model:"hktxjmmodel9",nodeStatu:"ACTIVE"},{shape:"hktxjm.zhanLue",appType:"liYiXGF",defaultName:"利益相关方",name:"利益相关方",`datas.placeholders`:"1",`datas.parentIdd`:"",`datas.extendField`:"其它1",idd:"node-5c6cb4d3-857c-41d9-908f-4ae68d5da60f",nodeVersion:"1",model:"hktxjmmodel9",nodeStatu:"ACTIVE"},{shape:"hktxjm.zhanLue",appType:"nengLi",defaultName:"能力",name:"能力",`datas.placeholders`:"1",`datas.parentIdd`:"node-5c6cb4d3-857c-41d9-908f-4ae68d5da60f",`datas.extendField`:"其它1",idd:"node-4fef4ea8-25f7-4e9c-8a20-752e99134ec8",nodeVersion:"1",model:"hktxjmmodel9",nodeStatu:"ACTIVE"},{shape:"hktxjm.zhanLue",appType:"nengLi",defaultName:"能力",name:"能力",`datas.placeholders`:"1",`datas.parentIdd`:"node-5c6cb4d3-857c-41d9-908f-4ae68d5da60f",`datas.extendField`:"其它1",idd:"node-9f252924-d128-4d31-b326-0f549452519d",nodeVersion:"1",model:"hktxjmmodel9",nodeStatu:"ACTIVE"},{shape:"hktxjm.zhanLue",appType:"yuanJing",defaultName:"愿景",name:"愿景",`datas.placeholders`:"1",`datas.parentIdd`:"node-5c6cb4d3-857c-41d9-908f-4ae68d5da60f",`datas.extendField`:"其它1",idd:"node-7f532b96-bc60-47d9-a394-ca4b5c97d7d0",nodeVersion:"1",model:"hktxjmmodel9",nodeStatu:"ACTIVE"}] as maps, 'hktxjmmodel9' as model
unwind maps as map
MERGE (s:hktxjm { model:model, idd:map.idd, nodeStatu:'ACTIVE' })
ON CREATE SET s = map, s.model = model
ON MATCH SET s += map
RETURN s
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Sep 14, 2022
@liseri
Copy link
Author

liseri commented Sep 14, 2022

I use new data to recheck the issue, also the problem; a->b, a->c, the query all return result is b has incoming a, c has incoming a, but a only has outgoing b, a do not include c.

@Jafeyyu
Copy link

Jafeyyu commented Sep 15, 2022

I encountered the same problem,and i think the reason is org.springframework.data.neo4j.core.mapping.DefaultNeo4jEntityConverter.populateFrom(MapAccessor, NodeDescription<?>, PersistentPropertyAccessor<?>, Predicate<Neo4jPersistentProperty>, boolean, Collection<Relationship>, Collection<Node>) avoid unnecessary re-assignment of values

@meistermeier meistermeier self-assigned this Sep 15, 2022
@meistermeier
Copy link
Collaborator

Could you create a database setup including the relationships? I tried to reproduce it on with the data from #2583 and also added the definition of the incoming relationships to the model. But all seems fine (for samples I thought it was worth looking at them). Would be good to get the problematic subset to figure out the problem.

@meistermeier meistermeier added status: waiting-for-feedback We need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged labels Sep 15, 2022
@liseri
Copy link
Author

liseri commented Sep 16, 2022

Sorry, forget to paste relationsips cql; I will give you a new simpler data(only 3 nodes and 2 rels) to test as below
create node

with [{shape:"hktxjm.zhanLue",appType:"ceDu",defaultName:"测度",name:"testCeDu1",description:"test",`datas.extendField`:"test",idd:"node-6edd138d-03e6-4b15-8cd2-4c2e930b75f1",nodeVersion:"1",model:"hktxjmmodel9",nodeStatu:"ACTIVE"},{shape:"hktxjm.zhanLue",appType:"ceDu",defaultName:"测度",name:"testCeDu2",description:"test2",`datas.extendField`:"test2",idd:"node-7c067fa8-50f7-47df-b43a-1e41c0c4006d",nodeVersion:"1",model:"hktxjmmodel9",nodeStatu:"ACTIVE"},{shape:"hktxjm.yingYong",appType:"yingYongY",defaultName:"域",name:"testYingYongY1",idd:"node-41498c56-7f82-4444-927a-39e73fc1bfa1",nodeVersion:"1",model:"hktxjmmodel9",nodeStatu:"ACTIVE"}] as maps, 'hktxjmmodel9' as model
unwind maps as map
MERGE (s:hktxjm { model:model, idd:map.idd, nodeStatu:'ACTIVE' })
ON CREATE SET s = map, s.model = model
ON MATCH SET s += map
RETURN s

create relationship

with [{sourceNodeIdd:"node-6edd138d-03e6-4b15-8cd2-4c2e930b75f1",targetNodeIdd:"node-41498c56-7f82-4444-927a-39e73fc1bfa1",edgeIdd:"edge-93e6c4f8-f06e-4136-835a-69d7d5f5696b",edgeMap:{shape:"hktxjm.guanXi",appType:"parent",defaultName:"父",name:"testParent1",idd:"edge-93e6c4f8-f06e-4136-835a-69d7d5f5696b"}},{sourceNodeIdd:"node-7c067fa8-50f7-47df-b43a-1e41c0c4006d",targetNodeIdd:"node-41498c56-7f82-4444-927a-39e73fc1bfa1",edgeIdd:"edge-7503965e-c9fa-4547-aba1-6a6df16c67cd",edgeMap:{shape:"hktxjm.guanXi",appType:"parent",defaultName:"父",name:"testParent2",idd:"edge-7503965e-c9fa-4547-aba1-6a6df16c67cd"}}] as lists, 'hktxjmmodel9' as model
unwind lists as item
MATCH (s:hktxjm { model:model, idd:item.sourceNodeIdd, nodeStatu:'ACTIVE' })
MATCH (t:hktxjm { model:model, idd:item.targetNodeIdd, nodeStatu:'ACTIVE' })
MERGE (s)-[r:guanXi {idd:item.edgeIdd}]->(t)
ON CREATE SET r = item.edgeMap
ON MATCH SET r += item.edgeMap
WITH item,model,s,r,t
MATCH(s2:hktxjm { model:model})-[r2:guanXi {idd:item.edgeIdd}]->(t2:hktxjm { model:model})
WHERE s.idd <> s2.idd or t.idd <> t2.idd
DELETE r2
RETURN s,collect(r),collect(t)

test findone(by node idd=node-41498c56-7f82-4444-927a-39e73fc1bfa1) it is normal has 2 incoming rels
the result is :

{
    "cell": "yingYongY",
    "name": "testYingYongY1",
    "description": null,
    "datas": {},
    "idd": "node-41498c56-7f82-4444-927a-39e73fc1bfa1",
    "model": "hktxjmmodel9",
    "nodeVersion": "1",
    "nodeStatu": "ACTIVE",
    "incomingEdges": [
        {
            "cell": "parent",
            "name": "testParent2",
            "description": null,
            "datas": {},
            "idd": "edge-7503965e-c9fa-4547-aba1-6a6df16c67cd",
            "otherSideNode": {
                "cell": "ceDu",
                "name": "testCeDu2",
                "description": "test2",
                "datas": {
                    "extendField": "test2"
                },
                "idd": "node-7c067fa8-50f7-47df-b43a-1e41c0c4006d",
                "model": "hktxjmmodel9",
                "nodeVersion": "1",
                "nodeStatu": "ACTIVE",
                "incomingEdges": null,
                "outgoingEdges": null,
                "banBenEdges": null
            }
        },
        {
            "cell": "parent",
            "name": "testParent1",
            "description": null,
            "datas": {},
            "idd": "edge-93e6c4f8-f06e-4136-835a-69d7d5f5696b",
            "otherSideNode": {
                "cell": "ceDu",
                "name": "testCeDu1",
                "description": "test",
                "datas": {
                    "extendField": "test"
                },
                "idd": "node-6edd138d-03e6-4b15-8cd2-4c2e930b75f1",
                "model": "hktxjmmodel9",
                "nodeVersion": "1",
                "nodeStatu": "ACTIVE",
                "incomingEdges": null,
                "outgoingEdges": null,
                "banBenEdges": null
            }
        }
    ],
    "outgoingEdges": null,
    "banBenEdges": null
}

test findAll, it is not normal, the node(idd=node-41498c56-7f82-4444-927a-39e73fc1bfa1) has only one incoming rel
the result is :

{
    "content": [
        {
            "cell": "ceDu",
            "name": "testCeDu1",
            "description": "test",
            "datas": {
                "extendField": "test"
            },
            "idd": "node-6edd138d-03e6-4b15-8cd2-4c2e930b75f1",
            "model": "hktxjmmodel9",
            "nodeVersion": "1",
            "nodeStatu": "ACTIVE",
            "incomingEdges": null,
            "outgoingEdges": [
                {
                    "cell": "parent",
                    "name": "testParent1",
                    "description": null,
                    "datas": {},
                    "idd": "edge-93e6c4f8-f06e-4136-835a-69d7d5f5696b",
                    "otherSideNode": {
                        "cell": "yingYongY",
                        "name": "testYingYongY1",
                        "description": null,
                        "datas": {},
                        "idd": "node-41498c56-7f82-4444-927a-39e73fc1bfa1",
                        "model": "hktxjmmodel9",
                        "nodeVersion": "1",
                        "nodeStatu": "ACTIVE",
                        "incomingEdges": null,
                        "outgoingEdges": null,
                        "banBenEdges": null
                    }
                }
            ],
            "banBenEdges": null
        },
        {
            "cell": "ceDu",
            "name": "testCeDu2",
            "description": "test2",
            "datas": {
                "extendField": "test2"
            },
            "idd": "node-7c067fa8-50f7-47df-b43a-1e41c0c4006d",
            "model": "hktxjmmodel9",
            "nodeVersion": "1",
            "nodeStatu": "ACTIVE",
            "incomingEdges": null,
            "outgoingEdges": [
                {
                    "cell": "parent",
                    "name": "testParent2",
                    "description": null,
                    "datas": {},
                    "idd": "edge-7503965e-c9fa-4547-aba1-6a6df16c67cd",
                    "otherSideNode": {
                        "cell": "yingYongY",
                        "name": "testYingYongY1",
                        "description": null,
                        "datas": {},
                        "idd": "node-41498c56-7f82-4444-927a-39e73fc1bfa1",
                        "model": "hktxjmmodel9",
                        "nodeVersion": "1",
                        "nodeStatu": "ACTIVE",
                        "incomingEdges": null,
                        "outgoingEdges": null,
                        "banBenEdges": null
                    }
                }
            ],
            "banBenEdges": null
        },
        {
            "cell": "yingYongY",
            "name": "testYingYongY1",
            "description": null,
            "datas": {},
            "idd": "node-41498c56-7f82-4444-927a-39e73fc1bfa1",
            "model": "hktxjmmodel9",
            "nodeVersion": "1",
            "nodeStatu": "ACTIVE",
            "incomingEdges": [
                {
                    "cell": "parent",
                    "name": "testParent1",
                    "description": null,
                    "datas": {},
                    "idd": "edge-93e6c4f8-f06e-4136-835a-69d7d5f5696b",
                    "otherSideNode": {
                        "cell": "ceDu",
                        "name": "testCeDu1",
                        "description": "test",
                        "datas": {
                            "extendField": "test"
                        },
                        "idd": "node-6edd138d-03e6-4b15-8cd2-4c2e930b75f1",
                        "model": "hktxjmmodel9",
                        "nodeVersion": "1",
                        "nodeStatu": "ACTIVE",
                        "incomingEdges": null,
                        "outgoingEdges": null,
                        "banBenEdges": null
                    }
                }
            ],
            "outgoingEdges": null,
            "banBenEdges": null
        }
    ],
    "pageable": {
        "sort": {
            "empty": true,
            "sorted": false,
            "unsorted": true
        },
        "offset": 0,
        "pageSize": 20,
        "pageNumber": 0,
        "unpaged": false,
        "paged": true
    },
    "last": true,
    "totalElements": 3,
    "totalPages": 1,
    "size": 20,
    "number": 0,
    "sort": {
        "empty": true,
        "sorted": false,
        "unsorted": true
    },
    "first": true,
    "numberOfElements": 3,
    "empty": false
}

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 16, 2022
@liseri
Copy link
Author

liseri commented Sep 22, 2022

@meistermeier hi, Has the problem recurred?

@meistermeier
Copy link
Collaborator

Unfortunately to get down to this issue, I was not able to reproduce the problem.
Can you please report the SDN version, you are using when observing the issue?

I also ran the following test multiple (a thousand) times for single and all results.

@Test
void testIncomingEdges() {
    //  var entity = repository.findByIdd("node-41498c56-7f82-4444-927a-39e73fc1bfa1");
    var entities = repository.findAll();
    var entity = entities.stream().filter(s -> s.getIdd().equals("node-41498c56-7f82-4444-927a-39e73fc1bfa1")).findFirst().get();
    Assertions.assertThat(entity.getEdgeIncoming()).hasSize(2);
}

@meistermeier meistermeier added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Sep 26, 2022
@liseri
Copy link
Author

liseri commented Sep 27, 2022

@meistermeier Sorry, I not provide sufficient details.
the sdn is:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-neo4j</artifactId>
            <version>2.7.2</version>
        </dependency>

The findAll repository code is used custom query:

Optional<TxjmNodeEntity> findOneByModelAndIdd(String model, String idd);

List<TxjmNodeEntity> findAllByModel(String model);

@Transactional(readOnly = true)
    @Query(value = "MATCH (s:hktxjm)\n" +
                   "WHERE s.model = $model AND s.nodeStatu = 'ACTIVE' \n" +
                   "WITH s :#{orderBy(#pageable)} SKIP $skip LIMIT $limit \n" +
                   "optional MATCH (s)-[r]-(t:hktxjm)\n" +
                   "WHERE type(r) in ['guanXi']\n" +
                   "RETURN s,collect(r), collect(t)",
            countQuery = "MATCH (s:hktxjm)\n" +
                    "WHERE s.model = $model AND s.nodeStatu = 'ACTIVE' \n" +
                    "RETURN count(s)"
    )
    Page<TxjmNodeEntity> queryAllNodes(String model, Pageable pageable);

The test code is:

@Test
    void testFindOne() {
        String model = "hktxjmmodel9";
        //findOne
        Optional<TxjmNodeEntity> entityForFindOne = txjmNodeEntityRepository.findOneByModelAndIdd(model,"node-41498c56-7f82-4444-927a-39e73fc1bfa1");
        
        Assertions.assertThat(entityForFindOne.get().getIncomingEdges()).hasSize(2);
    }

    @Test
    void testFindAll() {
        String model = "hktxjmmodel9";
        //findAll
        List<TxjmNodeEntity> entitiesForFindAll = txjmNodeEntityRepository.findAllByModel(model);
        TxjmNodeEntity entityFromFindAll = entitiesForFindAll.stream().filter(s -> s.getIdd().equals("node-41498c56-7f82-4444-927a-39e73fc1bfa1")).findFirst().get();

        Assertions.assertThat(entityFromFindAll.getIncomingEdges()).hasSize(2);
    }

    @Test
    void testCustomQueryAll() {
        String model = "hktxjmmodel9";
        //costum query all
        Page<TxjmNodeEntity> entitiesForCustomQueryAll = txjmNodeEntityRepository.queryAllNodes(model, Pageable.ofSize(20));
        TxjmNodeEntity entityFromCustomQueryAll = entitiesForCustomQueryAll.stream().filter(s -> s.getIdd().equals("node-41498c56-7f82-4444-927a-39e73fc1bfa1")).findFirst().get();

        Assertions.assertThat(entityFromCustomQueryAll.getIncomingEdges()).hasSize(2);
    }

The test result is :

image

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 27, 2022
@meistermeier
Copy link
Collaborator

That's interesting, I tried to reproduce it but still no chance. I created a (non-)reproducer https://github.com/meistermeier/neo4j-issues-examples/tree/master/gh-2592
It might be worth a look what I am doing different/wrong.

@meistermeier meistermeier added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Sep 29, 2022
@liseri
Copy link
Author

liseri commented Sep 30, 2022

@meistermeier hi, i add a new test fun in https://github.com/meistermeier/neo4j-issues-examples/pull/4, it is fail.
I want to try new snapshot version you mentioned in #2600 ,but I cannot get the 6.3.4 version.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 30, 2022
@meistermeier
Copy link
Collaborator

meistermeier commented Sep 30, 2022

The version is 6.3.4-GH-2600-SNAPSHOT not just 6.3.4.
Also you need to define Spring's snapshot (and milestone) repositories.

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-neo4j</artifactId>
    <version>6.3.4-GH-2600-SNAPSHOT</version>
</dependency>
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/snapshot</url>
        <releases>
            <enabled>false</enabled>
        </releases>
    </repository>
</repositories>

with this in place, the test runs smoothly.

@meistermeier meistermeier added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Oct 6, 2022
@liseri
Copy link
Author

liseri commented Oct 8, 2022

@meistermeier Hi, The test passed when I use the new snapshot version you provided. Thanks a lot. Looking forward to the release of the new Release version.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Oct 8, 2022
@meistermeier
Copy link
Collaborator

Thank you very much for your feedback. I will close this issue now and keep #2600 to have a single reference issue for the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: feedback-provided Feedback has been provided
Projects
None yet
Development

No branches or pull requests

4 participants