Cycles in family tree software
It seems you (and/or your company) have a fundamental misunderstanding of what a family tree is supposed to be.
Let me clarify, I also work for a company that has (as one of its products) a family tree in its portfolio, and we have been struggling with similar problems.
The problem, in our case, and I assume your case as well, comes from the GEDCOM format that is extremely opinionated about what a family should be. However this format contains some severe misconceptions about what a family tree really looks like.
GEDCOM has many issues, such as incompatibility with same sex relations, incest, etc... Which in real life happens more often than you'd imagine (especially when going back in time to the 1700-1800).
We have modeled our family tree to what happens in the real world: Events (for example, births, weddings, engagement, unions, deaths, adoptions, etc.). We do not put any restrictions on these, except for logically impossible ones (for example, one can't be one's own parent, relations need two individuals, etc...)
The lack of validations gives us a more "real world", simpler and more flexible solution.
As for this specific case, I would suggest removing the assertions as they do not hold universally.
For displaying issues (that will arise) I would suggest drawing the same node as many times as needed, hinting at the duplication by lighting up all the copies on selecting one of them.
there are some issues in this family tree I made
Using Mermaid JS, to obtain a graph,
It may also be helpful to see the shape of the abstraction used to create the tree structure.
As you can see in code -mermaid code- section,
With a one-dimensional flat set, it is possible to express node connections.
(Since enlarging the graph makes no practical sense,
I did not choose to enlarge any further. A tree with two or three generations is sufficient.)
I hope all this gives an idea.
PS:
On the additional question in the comments, I've edited the answer.
When using Mermaid, using the syntax in the example code --> 2 [ Aidem ]
,
You can use the same name on different nodes. For additional questions, reviewing and trying the documentation may get you closer to the answer.
graph TD
Root --> Liven
Root --> Aidem
Root --> Dimitri --> Oleg
Root --> Olga --> Oleg
Liven --> Milna
Aidem --> Milna
Milna --> Harmi
Oleg --> Harmi
Harmi --> 2[Aidem]
Mina --> 2[Aidem]
Root --> Mina
Fetching nested data with NEO4J in Family Tree
One way to approach it is using apoc.convert.toTree (using the plugin apoc).
This can create the tree structure that you are looking for. But, since your tree is bottom-up, the result will be same, meaning each node will point its parent. If you want to get the results as you want, using this method, you will have to change your relations.
For example, using this data:
MERGE (a:Person{key: 1, username: "SETHLORDM"})
MERGE (b:Person{key: 2})
MERGE (c:Person{key: 3})
MERGE (d:Person{key: 4})
MERGE (e:Person{key: 5})
MERGE (f:Person{key: 6})
MERGE (g:Person{key: 7})
MERGE (b)-[:CHILD_OF]-(a)
MERGE (c)-[:CHILD_OF]-(a)
MERGE (d)-[:CHILD_OF]-(b)
MERGE (e)-[:CHILD_OF]-(b)
MERGE (f)-[:CHILD_OF]-(c)
MERGE (g)-[:CHILD_OF]-(c)
and this query:
MATCH path = (p:Person {username: "SETHLORDM"})<-[r:CHILD_OF*..2]-(p2)
WITH collect(path) AS paths
CALL apoc.convert.toTree(paths)
YIELD value
RETURN value;
will give this result:
"_type": "Person",
"child_of": [
{
"_type": "Person",
"child_of": [
{
"_type": "Person",
"_id": 243,
"key": 5
},
{
"_type": "Person",
"_id": 242,
"key": 4
}
],
"_id": 240,
"key": 2
},
{
"_type": "Person",
"child_of": [
{
"_type": "Person",
"_id": 245,
"key": 7
},
{
"_type": "Person",
"_id": 244,
"key": 6
}
],
"_id": 241,
"key": 3
}
],
"_id": 239,
"key": 1,
"username": "SETHLORDM"
}
But changing the links to this:
MERGE (a)-[:CHILDREN]-(b)
MERGE (a)-[:CHILDREN]-(c)
MERGE (b)-[:CHILDREN]-(d)
MERGE (b)-[:CHILDREN]-(e)
MERGE (c)-[:CHILDREN]-(f)
MERGE (c)-[:CHILDREN]-(g)
And adjusting the query to:
MATCH path = (p:Person {username: "SETHLORDM"})-[r:CHILDREN*..2]->(p2)
WITH collect(path) AS paths
CALL apoc.convert.toTree(paths)
YIELD value
RETURN value;
Will provide:
{
"_type": "Person",
"_id": 246,
"children": [
{
"_type": "Person",
"_id": 247,
"children": [
{
"_type": "Person",
"_id": 249,
"key": 4
},
{
"_type": "Person",
"_id": 250,
"key": 5
}
],
"key": 2
},
{
"_type": "Person",
"_id": 248,
"children": [
{
"_type": "Person",
"_id": 252,
"key": 7
},
{
"_type": "Person",
"_id": 251,
"key": 6
}
],
"key": 3
}
],
"key": 1,
"username": "SETHLORDM"
}
Which is now similar to what you wanted...
Bonus: if you are using apoc, you can replace the MATCH
query by apoc.path.expandConfig
which should be more efficient to larger graphs.
Related Topics
Link Errors Using <Filesystem> Members in C++17
Class & Function Names Highlighting in Vim
Can Openssl on Windows Use the System Certificate Store
Debugging Template Instantiations
How to Estimate Memory Usage of Std::Map
Understanding Double Dispatch C++
How to Alloc a Executable Memory Buffer
Compile Time Triggered Range Check for Std::Vector
Are There Stackless or Heapless Implementation of C++
C++ Inherit from Multiple Base Classes with the Same Virtual Function Name
How to Typically/Always Use Std::Forward Instead of Std::Move
The Implementation of Std::Forward
Should a Move Constructor Take a Const or Non-Const Rvalue Reference
Simulating Key Press Events in MAC Os X
Correctly Reading a Utf-16 Text File into a String Without External Libraries