Search code examples
neo4jcyphergeneticsgenealogy

Neo4j cypher query for X-chromosome ancestors


In genetic genealogy X-chromosome data is useful linking to certain ancestors. This is well illustrated at: X-DNA Inheritance Chart

My Neo4j database has nodes for each Person and relationships connecting them of father and mother. Each node has a property sex (for the Person's gender; M or F). A female has two X-chromosomes, one from either parent. A male has one X-chromosome, always from the mother.

You can use reduce to see the genders involved in the inheritance from ancestors:

match p=(n:Person{RN:1})-[:father|mother*..20]->m 
return m.fullname as FullName
,reduce(status ='', q IN nodes(p)| status + q.sex) AS c 
order by length(p), c

So, starting with a male (RN:1), the result for c is MM for his father and MF for his mother, MMM for the paternal grandfather and MFM for the maternal grandfather, etc. This pattern shows that when c contains MM (two Ms together in sequence) that these are NOT contributing to the X-chromosome of the start Person.

I want to remove any node that has the MM pattern. It's easy to do this with external code, but I cannot figure out how to do it within the cypher query.


Solution

  • This should work for you:

    MATCH p=(n:Person { RN:1 })-[:father|mother*..20]->m
    WITH m, NODES(p) AS a
    WITH m, REDUCE(c = "", i IN RANGE(0, SIZE(a)-1)| CASE
      WHEN c IS NULL OR (i > 0 AND (a[i-1]).sex = "M" AND (a[i]).sex = "M") THEN
        NULL
      ELSE
        c + (a[i]).sex
      END ) AS c
    WHERE c IS NOT NULL
    RETURN m.fullName AS fullName, c
    ORDER BY LENGTH(c);
    

    And here is a console that demonstrates the results.