Reputation: 1294
I have two node types "Person" and "Company". There is also a relationship called "Shareholder", which can be from Person to Company or Company to Company (as companies can also hold shares in other companies). The Shareholder relationship has three properties "shareholding_start_date", "shareholding_end_date", "number_of_shares".
I want to be able to query a Company (call it c) by name, as well as provide a date (e.g. '2021-07-23'), and the query should return all Person/Company nodes that are shareholders of c at the date '2021-07-23' (i.e. shareholding_start_date < 2021-07-23 < shareholding_end_date). I also want to calculate the percentage based on 'number_of_shares'.
As an example, let's say there is a company called XYZ, and I want to know all it's shareholders on 2022-03-15. Suppose ABC has three shareholders ABC, DEF, GHI on this day (these can be either Person or Company nodes). ABC holds 30 shares, DEF holds 50 shares, GHI holds 120 shares.
The query should be something like this (obviously this is not cypher, but I'm unable to express it in any other way!):
Company.name = "XYZ"
and Shareholder.shareholding_start_date <= 2022-03-15
and SHareholder.shareholding_end_date >= 2022-03-15
Returns something like:
ABC 15%, DEF 25%, GHI 60%
Upvotes: 0
Views: 71
Reputation: 881
MATCH (c:Company {name:"ABC"})<-[r:Shareholder]-(s)
WHERE r.shareholding_start_date <= Date("2022-03-15")
AND r.shareholding_end_date >= DATE("2022-03-15")
WITH c,
collect(s) as shareholders,
collect(r) as rels,
sum(r.number_of_shares) AS totalShares
UNWIND range(0, size(rels) - 1) AS i
RETURN shareholders[i].name AS shareholder,
100.0 * rels[i].numberOfShares/totalShares as percentTotalShares
For more examples of percent of total in Neo4j, see this blog post. https://medium.com/neo4j/kickstart-your-transition-from-sql-analytic-and-window-functions-to-neo4j-987d67f7fdb4
To show shareholders of shareholders to an arbitrary distance from your target company as requested in the comment, you might use this approach.
MATCH p=(c:Company {name:"ABC"})<-[r:Shareholder*1..3]-(holder)
WHERE all(holding IN relationships(p) WHERE holding.shareholding_start_date <= Date('2022-03-15') <= holding.shareholding_end_date)
WITH
length(p) - 1 AS distanceToTargetCompany,
nodes(p)[-2].name AS companyName,
holder,
relationships(p)[-1].number_of_shares AS number_of_shares
WITH
distanceToTargetCompany,
companyName,
collect(DISTINCT {shareHolder: holder.name, numberOfShares: number_of_shares}) as shareHolders
WITH
distanceToTargetCompany,
companyName,
shareHolders,
reduce(acc=0, company in shareHolders | acc + company['numberOfShares']) AS totalShares
RETURN
distanceToTargetCompany,
companyName,
reduce(acc=[], company in shareHolders | acc + company{.*, percentTotal:100.0 * company['numberOfShares']/totalShares}) AS shareHolders
ORDER BY distanceToTargetCompany, companyName
Upvotes: 2