Redis Graph: How to return distinct nodes asJson - cypher

Using GRAPH.QUERY mykey "MATCH (node:m000) RETURN toJson(node)" I get the following:
[
{
"key": "000", "containerid": "10000" // id 1
},
{
"key": "001", "containerid": "10001" // id 2
},
{
"key": "000", "containerid": "10000" // id 3
}
]
I would like to not get the duplicate item in the results (the last item above).
I tried DISTINCT: GRAPH.QUERY mykey "MATCH (node:m000) RETURN DISTINCT toJson(node)" but that returns all records, presumably because the node id IS unique on each record (even though it isn't in the node properties that are being serialized).
Obviously I can filter the results myself but is there a way to do that in the graph command itself?
Thanks, Murray.

As you said, the id property is unique, thus DISTINCT will not be able to filter out the duplicate without further manual filtering.
If you don't care about the id of the entity, you can write something like:
GRAPH.QUERY mykey MATCH (node:m000) RETURN DISTINCT toJson(properties(node)), toJson(labels(node)), which will filter the duplicate out.

GRAPH.QUERY g "CREATE ({x:1, y:2, z:3}), ({x:1, y:2, z:3}), ({x:1, y:2, z:4})"
GRAPH.QUERY g "MATCH (a) RETURN toJSON(properties(a))"
1) 1) "toJSON(properties(a))"
2) 1) 1) "{\"x\": 1, \"y\": 2, \"z\": 3}"
2) 1) "{\"x\": 1, \"y\": 2, \"z\": 3}"
3) 1) "{\"x\": 1, \"y\": 2, \"z\": 4}"
If you need just the combinations of properties you can do the following:
GRAPH.QUERY g "MATCH (a) WITH distinct(properties(a)) as b return toJSON(b)"
1) 1) "toJSON(b)"
2) 1) 1) "{\"x\": 1, \"y\": 2, \"z\": 3}"
2) 1) "{\"x\": 1, \"y\": 2, \"z\": 4}"
BTW, to get it as a single JSON:
GRAPH.QUERY g "MATCH (a) RETURN toJSON(collect(distinct properties(a)))"
1) 1) "toJSON(collect(distinct properties(a)))"
2) 1) 1) "[{\"x\": 1, \"y\": 2, \"z\": 3}, {\"x\": 1, \"y\": 2, \"z\": 4}]"

Related

Query group by a column and return JSON

I have a table as below:
id
mid
handphone
coupono
status
1
1
0811111111
1
1
2
1
08222222222
2
1
3
1
08222222222
3
1
4
1
08222222222
4
1
5
1
08111111111
5
1
6
2
08333333333
6
1
7
2
08333333333
7
1
8
2
08444444444
8
1
-----
-----
---------------
--------
-------
I want to query the table using WHERE clause on mId column and filtered the couponno or listed on handphone number. How to query that?
The result that I want is:
{
"08111111111": [{
"Id": 1,
"CouponNo": 1,
"Status": 1
}, {
"Id": 5,
"CouponNo": 5,
"Status": 1
}],
"08222222222": [{
"Id": 2,
"CouponNo": 2,
"Status": 1
}, {
"Id": 3,
"CouponNo": 3,
"Status": 1
}, {
"Id": 4,
"CouponNo": 4,
"Status": 1
}]
}
Requiring Handphone to be object keys in your JSON makes it difficult to produce from SQL and probably won't scale well on the receiving side either as you add more data over time.
Here is some pivot-based SQL that will produce your desired JSON...
create table dbo.PivotJsonStuff (
Id int,
[Mid] int,
Handphone varchar(11),
CouponNo int,
Status int
);
insert dbo.PivotJsonStuff (Id, [Mid], Handphone, CouponNo, Status)
values
(1, 1, '08111111111', 1, 1),
(2, 1, '08222222222', 2, 1),
(3, 1, '08222222222', 3, 1),
(4, 1, '08222222222', 4, 1),
(5, 1, '08111111111', 5, 1),
(6, 2, '08333333333', 6, 1),
(7, 2, '08333333333', 7, 1),
(8, 2, '08444444444', 8, 1);
select
[08111111111] = json_query([08111111111]),
[08222222222] = json_query([08222222222])
from (
select Handphone,
[JSON] = (
select PJS2.Id, PJS2.CouponNo, PJS2.Status
from dbo.PivotJsonStuff PJS2
where PJS2.Handphone = PJS1.Handphone
for json path
)
from dbo.PivotJsonStuff PJS1
group by Handphone
) src
pivot (max([JSON]) for Handphone in ([08111111111], [08222222222])) pvt
for json path, without_array_wrapper;
{
"08111111111": [
{
"Id": 1,
"CouponNo": 1,
"Status": 1
},
{
"Id": 5,
"CouponNo": 5,
"Status": 1
}
],
"08222222222": [
{
"Id": 2,
"CouponNo": 2,
"Status": 1
},
{
"Id": 3,
"CouponNo": 3,
"Status": 1
},
{
"Id": 4,
"CouponNo": 4,
"Status": 1
}
]
}

How to I modify arrays inside of a map in Kotlin

I am working with a map with strings as keys and arrays as values. I would like to adjust the map to be the original strings and change the arrays to the average values.
The original map is:
val appRatings = mapOf(
"Calendar Pro" to arrayOf(1, 5, 5, 4, 2, 1, 5, 4),
"The Messenger" to arrayOf(5, 4, 2, 5, 4, 1, 1, 2),
"Socialise" to arrayOf(2, 1, 2, 2, 1, 2, 4, 2)
)
What I have tried to do is:
val averageRatings = appRatings.forEach{ (k,v) -> v.reduce { acc, i -> acc + 1 }/v.size}
However this returns a Unit instead of a map in Kotlin. What am I doing wrong? I am working through a lambda assignment and they want us to use foreach and reduce to get the answer.
You can use forEach and reduce, but it's overkill, because you can just use mapValues and take the average:
val appRatings = mapOf(
"Calendar Pro" to arrayOf(1, 5, 5, 4, 2, 1, 5, 4),
"The Messenger" to arrayOf(5, 4, 2, 5, 4, 1, 1, 2),
"Socialise" to arrayOf(2, 1, 2, 2, 1, 2, 4, 2)
)
val averages = appRatings.mapValues { (_, v) -> v.average() }
println(averages)
Output:
{Calendar Pro=3.375, The Messenger=3.0, Socialise=2.0}
You can do this with mapValues function:
val appRatings = mapOf(
"Calendar Pro" to arrayOf(1, 5, 5, 4, 2, 1, 5, 4),
"The Messenger" to arrayOf(5, 4, 2, 5, 4, 1, 1, 2),
"Socialise" to arrayOf(2, 1, 2, 2, 1, 2, 4, 2)
)
val ratingsAverage = appRatings.mapValues { it.value.average() }
You already got some answers (including literally from JetBrains?? nice) but just to clear up the forEach thing:
forEach is a "do something with each item" function that returns nothing (well, Unit) - it's terminal, the last thing you can do in a chain, because it doesn't return a value to do anything else with. It's basically a for loop, and it's about side effects, not transforming the collection that was passed in and producing different data.
onEach is similar, except it returns the original item - so you call onEach on a collection, you get the same collection as a result. So this one isn't terminal, and you can pop it in a function chain to do something with the current set of values, without altering them.
map is your standard "transform items into other items" function - if you want to put a collection in and get a different collection out (like transforming arrays of Ints into single Int averages) then you want map. (The name comes from mapping values onto other values, translating them - which is why you always get the same number of items out as you put in)

Postgres Build Complex JSON Object from Wide Column Like Design to Key Value

I could really use some help here before my mind explodes...
Given the following data structure:
SELECT * FROM (VALUES (1, 1, 1, 1), (2, 2, 2, 2)) AS t(day, apple, banana, orange);
day | apple | banana | orange
-----+-------+--------+--------
1 | 1 | 1 | 1
2 | 2 | 2 | 2
I want to construct a JSON object which looks like the following:
{
"data": [
{
"day": 1,
"fruits": [
{
"key": "apple",
"value": 1
},
{
"key": "banana",
"value": 1
},
{
"key": "orange",
"value": 1
}
]
}
]
}
Maybe I am not so far away from my goal:
SELECT json_build_object(
'data', json_agg(
json_build_object(
'day', t.day,
'fruits', t)
)
) FROM (VALUES (1, 1, 1, 1), (2, 2, 2, 2)) AS t(day, apple, banana, orange);
Results in:
{
"data": [
{
"day": 1,
"fruits": {
"day": 1,
"apple": 1,
"banana": 1,
"orange": 1
}
}
]
}
I know that there is json_each which may do the trick. But I am struggling to apply it to the query.
Edit:
This is my updated query which, I guess, is pretty close. I have dropped the thought to solve it with json_each. Now I only have to return an array of fruits instead appending to the fruits object:
SELECT json_build_object(
'data', json_agg(
json_build_object(
'day', t.day,
'fruits', json_build_object(
'key', 'apple',
'value', t.apple,
'key', 'banana',
'value', t.banana,
'key', 'orange',
'value', t.orange
)
)
)
) FROM (VALUES (1, 1, 1, 1), (2, 2, 2, 2)) AS t(day, apple, banana, orange);
Would I need to add a subquery to prevent a nested aggregate function?
Use the function jsonb_each() to get pairs (key, value), so you do not have to know the number of columns and their names to get a proper output:
select jsonb_build_object('data', jsonb_agg(to_jsonb(s) order by day))
from (
select day, jsonb_agg(jsonb_build_object('key', key, 'value', value)) as fruits
from (
values (1, 1, 1, 1), (2, 2, 2, 2)
) as t(day, apple, banana, orange),
jsonb_each(to_jsonb(t)- 'day')
group by 1
) s;
The above query gives this object:
{
"data": [
{
"day": 1,
"fruits": [
{
"key": "apple",
"value": 1
},
{
"key": "banana",
"value": 1
},
{
"key": "orange",
"value": 1
}
]
},
{
"day": 2,
"fruits": [
{
"key": "apple",
"value": 2
},
{
"key": "banana",
"value": 2
},
{
"key": "orange",
"value": 2
}
]
}
]
}

In PostgreSQL, what's the best way to select an object from a JSONB array?

Right now, I have an an array that I'm able to select off a table.
[{"_id": 1, "count: 3},{"_id": 2, "count: 14},{"_id": 3, "count: 5}]
From this, I only need the count for a particular _id. For example, I need the count for
_id: 3
I've read the documentation but I haven't been able to figure out the correct way to get the object.
WITH test_array(data) AS ( VALUES
('[
{"_id": 1, "count": 3},
{"_id": 2, "count": 14},
{"_id": 3, "count": 5}
]'::JSONB)
)
SELECT val->>'count' AS result
FROM
test_array ta,
jsonb_array_elements(ta.data) val
WHERE val #> '{"_id":3}'::JSONB;
Result:
result
--------
5
(1 row)

How get last data from sorted set?

I saw a Redis tutorial. For my case there is a function: ZREVRANGEBYSCORE
But I dont understand how get last one data via this function.
I tried ZREVRANGEBYSCORE myzset 0 1 for get last data row
Assuming "last data" means the item with the largest score, use the ZREVRANGEBYSCORE command in the following manner:
ZREVRANGEBYSCORE <key> +inf -inf LIMIT 0 1
My example on Node.js. Get last 5 elements from sorted set.
redis.zadd('key1', 0, 'val0');
redis.zadd('key1', 2, 'val2');
redis.zadd('key1', 3, 'val3');
redis.zadd('key1', 4, 'val4');
redis.zadd('key1', 6, 'val6');
redis.zadd('key1', 8, 'val8');
redis.zadd('key1', 11, 'val11');
redis.zadd('key1', 21, 'val21');
setTimeout(() => {
redis.zrange('key1', -5, -1, (error, result) => {
console.log('result:', result);
});
}, 1000);
how about ZREVRANGEBYSCORE myzset 0 0?
redis> zadd score 100 Kenny 100 May 20 Mary 100 Doe 50 Foo
(integer) 5
redis> zrevrange score 0 0
1) "William"
redis> zrevrangebyscore score +inf -inf
1) "William"
2) "May"
3) "Kenny"
4) "Doe"
5) "Mary"
redis> zrevrangebyscore score +inf -inf withscores
1) "William"
2) "100"
3) "May"
4) "100"
5) "Kenny"
6) "100"
7) "Doe"
8) "100"
9) "Mary"
10) "20"