I interpret your question to be something like, with nodes in tree structures, how to set properties on a higher order node to the sum of the properties of its lower order nodes. I'm not sure if you only care about a root node reflecting the sum of its leaves and branches, or if you need each relative superior to reflect the sum of its inferiors. You haven't said anything about the depth of your tree (your example has one root and two leaves) or whether any node in the tree can contribute values or only the leaves, so I'll give a general answer that you'll have to apply to your structure.
A generic pattern to sum a tree in its root could be
MATCH (root:Root)-[:BRANCH*]->(b) // N.B. label the root so you can better control the starting point of your pattern
WITH root, SUM(b.value) as value
SET root.value = value
If the root also contains a value you could do.
SET root.sum = root.value + value
leaving root.value
intact. You'll have to figure out what these nodes and values are–I'll assume in the following that any node in the tree, not just the leaves, can have real values, so I'll keep the value of a node separate from the sum of its relative tree. If the sum operation alters the values summed it gives different results on the second run, which is probably not desired.
A generic pattern to sum the immediate inferiors in a superior would be similar, but without the label restriction on the root and removing the variable depth modifier on the relationship
MATCH (superior)-[:BRANCH]->(inferior)
WITH superior, SUM(inferior.value) as sum
SET superior.sum = superior.value + sum
This query doesn't do a good job transitively, since it only gets the value of inferiors not their sums, and if it were to get the sums it would get different sums depending on the order in which these local sums where calculated–the tendency would be to loose values deeper in the structure because the more shallow sums are calculated first. The reverse is true for the first query if used to set the sums of intermediate nodes, here the risk is that the more deeply nested values are summed first, and are then represented twice in the more shallow sums.
To get each intermediate node in the tree to sum up all it's subordinate nodes at any depth but without double counting or losing values you can use the local summing query, you just need to impose the correct order. One way to do that is to match all the paths of any depth in the tree, and for each end node of such a path match it as a local superior to its local inferiors (b
and l
below). Then collect the inferiors per superior, and order the results by the length of the path, ensuring that the patterns that are deepest into the tree are handled first. Then accumulate the correct sum from the inferior nodes. If the inferiors are leafs they have no sum of their own so use their value, otherwise use the sum; and any node is missing value then use 0. This is handled by COALESCE
. The value of each node is here included in its own sum, but that's up to you. By ordering the results of the MATCH
and by doing the accumulation not when traversing but when setting the property, you can expect the aggregation to step through the tree in the correct order.
MATCH path=(r:Root)-[:BRANCH*0..]->(b), b-[:BRANCH]->l
WITH b, length(path) as depth, collect(l) as ls
ORDER BY depth desc
SET b.sum = REDUCE(acc = COALESCE(b.value,0), l IN ls | acc + COALESCE(l.sum, l.value, 0))
RETURN ID(b) AS id, depth, b.sum AS sum
Here's a sample data set to try the query on. Some nodes in the tree have the value property and some don't.
This should work for one or many trees, just label the root nodes.
Don't set numeric values as strings: "1.0" + "2.0" = "1.02.0"
.
There is no straightforward way to do this without explicitly naming the properties. There may be some workaround, but you'd have to ask questions about that separately.