Neo4j compare sums from different queries and display result - neo4j

Is there a way that i compare results from different queries? Could the following queries be written in a single query together with the return for the wanted result?
Query1: Returns countries and SUM from all points given by countries that are not part of their region.
MATCH (c:Country)
with c
MATCH (c)-[vFrom:vote_from]->(vP:vote_points)-[vFor:vote_for]->(c2:Country)
with c,c2,vP
where not c.region=c2.region
return c2.name,sum(toInteger(vP.points))
Example return from Query1:
"Monaco" 11
"Montenegro" 34
"France" 359
"Cyprus" 600
"Romania" 837
Query2: Returns countries and SUM from all points given by countries that are part of their region.
MATCH (c:Country)
with c
MATCH (c)-[vFrom:vote_from]->(vP:vote_points)-[vFor:vote_for]->(c2:Country)
with c,c2,vP
where c.region=c2.region
return c2.name,c.name,sum(toInteger(vP.points))
Example return from Query2:
"Monaco" 35
"Montenegro" 66
"France" 157
"Cyprus" 102
"Romania" 255
Wanted result:
"Monaco" 35
"Montenegro" 66

Assuming that you are looking for cases where in-region point totals exceed out-of-region totals, this query may work for you:
MATCH (c:Country)-[:vote_from]->(vP:vote_points)-[:vote_for]->(c2:Country)
WITH c2,
REDUCE(s={in: 0, out: 0}, x IN COLLECT({reg: c.region, pts: toInteger(vP.points)}) |
CASE WHEN x.reg=c2.region
THEN {in: s.in + x.pts, out: s.out}
ELSE {in: s.in, out: s.out + x.pts}
END) AS res
WHERE res.in > res.out
RETURN c2.name AS name, res.in AS points

Related

Return different values depending on if a value is between numbers in Google Sheets

I have a value, let's say 138. I need a way to check what % it corresponds to. In this case 138 is between 135 and 164 so it must return 34%.
If value is less than 75 return 0%.
If value is more than 285 return max which is 60%.
Everything is in the same Google Spreadsheet. The table with % is in a different sheet named RENDIMENT. To look for values in that sheet I use =RENDIMENT!X7
Table with % depending on minium and maxium value
I finally have it. I ended up with this code:
=IFS(E5<RENDIMENT!$X$7;0%; C5=true;RENDIMENT!$W$16; AND(E5>=RENDIMENT!$X$7;E5<=RENDIMENT!$Y$7);RENDIMENT!$W$7; AND(E5>=RENDIMENT!$X$8;E5<=RENDIMENT!$Y$8);RENDIMENT!$W$8; AND(E5>=RENDIMENT!$X$9;E5<=RENDIMENT!$Y$9);RENDIMENT!$W$9; AND(E5>=RENDIMENT!$X$10;E5<=RENDIMENT!$Y$10);RENDIMENT!$W$10; AND(E5>=RENDIMENT!$X$11;E5<=RENDIMENT!$Y$11);RENDIMENT!$W$11; AND(E5>=RENDIMENT!$X$12;E5<=RENDIMENT!$Y$12);RENDIMENT!$W$12; AND(E5>=RENDIMENT!$X$13;E5<=RENDIMENT!$Y$13);RENDIMENT!$W$13; AND(E5>=RENDIMENT!$X$14;E5<=RENDIMENT!$Y$14);RENDIMENT!$W$14; E5>RENDIMENT!$X$15;RENDIMENT!W15)
lets say your value is in A1, use:
=IFNA(VLOOKUP(A1, {0, 0%; RENDIMENT!X7:X, RENDIMENT!W7:W}, 2, 1))
or:
=IFNA(VLOOKUP(A1; {0\ 0%; RENDIMENT!X7:X\ RENDIMENT!W7:W}; 2; 1))

Finding the "GAP" in node values ? or next?

Let say I have a nodes with values a multiples of 10. I want to find the first GAP in the values.
Here is how I would do it in numpy :
> np.where(np.diff([11,21,31,51,61,71,91]) > 10)[0][0] + 2
> 4 i.e. 41
How would I do this in Cypher... ?
match (n) where n.val % 10 = 1
with n.val
order by val ....???
I'm using RedisGraph.
PS>
if no GAP it should return the next value i.e. biggest + 10, if possible !
I'm not sure if this is the most performant solution, but you can accomplish this using a combination of collect() and list comprehensions:
MATCH (n) WHERE n.val % 10 = 1 WITH n.val AS val ORDER BY n.val // collect ordered vals
WITH collect(val) AS vals // combine vals into array
WITH vals, [idx IN range(0, size(vals) + 1) WHERE vals[idx + 1] - vals[idx] > 10] AS gaps // find first index with diff > 10
RETURN vals[gaps[0]] + 10 // return missing value
To additionally return the next-biggest value if no gaps are found, change the RETURN clause to use a CASE statement:
RETURN CASE size(gaps) WHEN 0 THEN vals[-1] + 10 ELSE vals[gaps[0]] + 10 END

How do I find the maximum value between several specific nodes in neo4j?

EXAMPLE:
A unidirectional graph of the following type is given:
CREATE
(b0:Bar {id:1, value: 1}),
(b1:Bar {id:2, value: 4}),
(b2:Bar {id:3, value: 3}),
(b3:Bar {id:4, value: 5}),
(b4:Bar {id:5, value: 9}),
(b5:Bar {id:6, value: 7}),
(b0)-[:NEXT_BAR]->(b1),
(b1)-[:NEXT_BAR]->(b2),
(b2)-[:NEXT_BAR]->(b3),
(b3)-[:NEXT_BAR]->(b4),
(b4)-[:NEXT_BAR]->(b5);
MATCH (b1)->[*1..5]->(b2)->(b3)->[*1..5]->(b4)
WHERE // here you need to write a condition that the maximum value between the value of nodes b3 and b4 is greater than the maximum value of nodes b1 and b2
RETURN //b1_b2_max, b3_b4_max
In other words, the result should be as follows:
b1_b2_max | b3_b4_max
4 | 9
Can you tell me how I can find aggregated information between certain nodes (including these nodes)?
What should my request look like?
You could do something like this to get the right values.
// start with a set of slices you would like to get the max from
WITH [[1,3],[3,5]] AS slices
// match the path you want to get the slices from
MATCH path=(:Bar {id: 1})-[:NEXT_BAR*..5]->(end:Bar)
WHERE NOT (end)-->()
WITH slices, path
// look at the nodes in each slice of the path
UNWIND slices AS slice
// find the max value in the slice
UNWIND nodes(path)[slice[0]..slice[1]] AS b
RETURN 'b' + toString(slice[0]) + '_b' + toString(slice[1]-1) + '_max', max(b.value) AS max_value
Rather than returning the slice and max values in rows you can instead collect them as pairs and convert that to a map using apoc.map.fromPairs. Then access specific values in the map and return them as columns.
WITH [[1,3],[3,5]] AS slices
MATCH path=(:Bar {id: 1})-[:NEXT_BAR*..5]->(end:Bar)
WHERE NOT (end)-->()
WITH slices, path
UNWIND slices AS slice
UNWIND nodes(path)[slice[0]..slice[1]] AS b
WITH ['b' + toString(slice[0]) + '_b' + toString(slice[1]-1) + '_max', max(b.value)] AS pair
WITH collect(pair) AS pairs
RETURN apoc.map.fromPairs(pairs)['b1_b2_max'] AS b1_b2_max,
apoc.map.fromPairs(pairs)['b3_b4_max'] AS b3_b4_max

Neo4j Cypher round value

I have the following Cypher:
MATCH (v:Value)-[:CONTAINS]->(hv:HistoryValue)
WHERE v.id = {valueId}
OPTIONAL MATCH (hv)-[:CREATED_BY]->(u:User)
WHERE {fetchCreateUsers}
WITH u, hv ORDER BY hv.createDate DESC
WITH count(hv) as count, count(hv) / {maxResults} as step, COLLECT({userId: u.id, historyValueId: hv.id, historyValue: hv.originalValue, historyValueCreateDate: hv.createDate}) AS data
RETURN REDUCE(s = [], i IN RANGE(0, count - 1, CASE step WHEN 0 THEN 1 ELSE step END) | s + data[i]) AS result, step, count
right now:
count(hv) = 260
{maxResults} = 100
The step variable equals 2 but I expect round(260/100) = 3
I tried the following round(count(hv) / {maxResults}) as step but step is still 2.
How to fix my query in order to get a proper round (3 as step variable in this particular case)?
Use toFloat() in one of the values:
return round(toFloat(260) / 100)
Output:
╒═══════════════════════════╕
│"round(toFloat(260) / 100)"│
╞═══════════════════════════╡
│3 │
└───────────────────────────┘
You're currently doing integer division. If you enter return 260/100 you'll get 2, and that's the value that gets rounded (though there's nothing to round, so you get 2 back).
You need to be working with floating point values. You can do this by having maxResults have an explicit decimal (100.0), or use toFloat() around either maxResults or the count. Both return 260/100.0 and return toFloat(260)/100 or return 260/toFloat(100) will result in 2.6. If you round() that you'll get your expected 3 value.

Ruby aggregate function with model

I have a product model in my ruby on rails application which has name,endorsement and expense attributes.
I need to write a query that list all records, but for every record I need to calculate endorsement-expense as income value. That seems to be ok. However, I need to sum all of the incomes consequtively as well.
For example my records are like these:
Name Endorsement Expense
X 100 25
Y 20 17
X 60 55
T 178 78
I need to list those values as:
Name Endorsement Expense Income Total Income
X 100 25 75 75
Y 20 17 3 78
X 60 55 5 83
T 178 78 100 183
How can I do that ?
Thanks.
rows = Product.select('name,endorsement,expense, (endorsement-expense) as income')
total_income = 0
rows.each do |row|
total_income += row.income
puts "#{row.name}, #{row.endorsement}, #{row.expense}, #{row.income}, #{total_income}"
end
You can also do it with a total income for each product:
products = Product.select("(endorsement - expense) AS 'income', name, endorsement, created_at, null as total")
products.each do |p|
p.total = Product.select("sum(endorsement) - sum(expense) AS 'total'").where(name: p.name).where("created_at <= ?", p.created_at).group('name').last.total
end
You can apply inject function to accumulate total income.
It will look something like this:
products.inject{|sum, product| sum += (product.endorsement - product.expense }

Resources