How to group field as array in sequlize? - sql

I have a sql table products:
+-----------+------+--------+
| productid | rate | name |
+-----------+------+--------+
| 100 | 80 | orange |
| 100 | 10 | orange |
| 102 | 100 | banana |
+-----------+------+--------+
I want to group by productid all the rates to array..
How to get using sequelize the following object (via find method)?
{
products: [{
productid: 100,
name: 'orange',
rate: [ 80, 10 ]
},
{
productid: 102,
name: 'banana'
rate: [100]
}
]
}

Suppose your table name is demo table
SELECT *
FROM demo frst, demo snd
WHERE frst.productid = snd.productid
Group By frst.productid;
this will give the expected result in the sql, if you use sequelize than it will give the same result i think so or some what you will have to modified after response

Related

Create a nested json with column values as key-value pairs

I am trying to build a JSON from the following tables
table : car_makers
+------+-------------+---------+
| cmid | companyname | country |
+------+-------------+---------+
| 1 | Toyota | Japan |
| 2 | Volkswagen | Germany |
| 3 | Nissan | Japan |
+------+-------------+---------+
Table : cars
+------+---------+-----------+
| cmid | carname | cartype |
+------+---------+-----------+
| 1 | Camry | Sedan |
| 1 | Corolla | Sedan |
| 2 | Golf | Hatchback |
| 2 | Tiguan | SUV |
| 3 | Qashqai | SUV |
+------+---------+-----------+
I am trying to create a nested JSON of this structure :
{
"companyName": "Volkswagen",
"carType": "Germany",
"cars": {
"Tiguan": "SUV",
"Golf": "Hatchback"
}
}
but the best I could do with the this query
select json_build_object('companyName',companyName, 'carType', country, 'cars', JSON_AGG(json_build_object('carName', carName, 'carType', carType) ))
from car_makers cm
join cars c on c.cmid = cm.cmid
group by companyName,country
is this -
{
"companyName": "Volkswagen",
"carType": "Germany",
"cars": [
{
"carName": "Tiguan",
"carType": "SUV"
},
{
"carName": "Golf",
"carType": "Hatchback"
}
]
}
So, how can I correct my current query to replace the nested json array with a json element of key-value pairs from column values ?
here is the fiddle with sample data and the query I have tried
You can use json_object_agg:
select json_build_object('companyName', c.companyName,
'country', c.country, 'cars', json_object_agg(c1.carName, c1.carType))
from car_makers c join cars c1 on c.cmid = c1.cmid
group by c.companyName, c.country
See fiddle.

Transform DataFrame to list of dictionaries where column name is a value of key:value pair

I have a panda DataFrame as follow
|---------------------|------------------|------------------|
| A | B | C |
|---------------------|------------------|------------------|
| abc | 34 | 8 |
|---------------------|------------------|------------------|
| abc | | 12 |
|---------------------|------------------|------------------|
| abc | 6 | 321 |
|---------------------|------------------|------------------|
I would like to conver it to a list of dictionary like this:
[
{
name: "A",
value: "abc"
},
{
name: "B",
value: 34
},
{
name: "C",
value: 8
}
]
There are several way to do it with a lot of data manipulation but I am looking for one that is straightforward if it exists
Thank you for your help
[[{'name':k, 'value':v} for k,v in x.items()] for x in df.to_dict(orient='records')]
This would probably work, not sure it is straightforward though.

Same query selects different data with row_number()

Let´s say I have two tables. The first table represents Accounts and the second table represents Characters. Tables are connected with "AccountId" column. According to o game, characters are connected to accounts and every account can contain 4 characters.
In my website I have two pages. The first page is called "Characterlist.php" and generates all characters in game with one specific Authority (Column in Accounts table) which would be equal to 0.
I'm using this query:
$query = "WITH
Acc AS
(SELECT AccountId, Authority
FROM Account
WHERE Authority = '0'),
Char AS
(SELECT Character.*
FROM Character, Acc
WHERE Character.AccountId = Acc.AccountId),
Res AS
(SELECT *,
ROW_NUMBER() OVER
(ORDER BY Reput DESC) AS row_number
FROM Char)
SELECT Res.Class,
Res.Name,
Res.Level,
Res.HeroLevel,
Res.Reput,
Res.row_number
FROM Res
WHERE Res.row_number >= '$charlistpagemin'
AND Res.row_number <= '$charlistpagemax'";
$charlistpagemin and $vharlistpagemax are php variables that I'm using to divide whole character list to several pages.
When I search characters of my testing account, their position according to their Reputation generated and ordered by row_number() is alright.
Then I have the second page userpanel.php which is shown only to signed users where they can see their game characters in another list.
I'm using almost the same query, just with different rules in the end.
$query =
"WITH
Acc AS
(SELECT AccountId,
Authority
FROM Account
WHERE Authority = '0'),
Char AS
(SELECT Character.*
FROM Character, Acc
WHERE Character.AccountId = Acc.AccountId),
Res AS
(SELECT *,
ROW_NUMBER()
OVER (ORDER BY Reput DESC) AS row_number FROM Char)
SELECT Res.AccountId,
Res.Class,
Res.Name,
Res.Level,
Res.HeroLevel,
Res.Reput,
Res.row_number
FROM Res
WHERE Res.AccountId = '" . $_SESSION["accountid"] . "'";
And there is the problem. Their position according to Reputation is different (bad) than in characterlist.php. Where is the problem?
Edit:
The table "Account" looks like:
AccountId | Authority | ... |
The table "Character" looks like:
AccountId | Class | Name | Level | HeroLevel | Reput | ... |
My testing account has
AccountId: xxx | Authority: 0 | ... |
And has Characters
AccountId: XXX | Class: Dobrodruh | Name: Kryploij1 | Level: 15 | Herolevel: 0 | Reput: 0 | ... |
AccountId: XXX | Class: Dobrodruh | Name: Kryploid2 | Level: 15 | Herolevel: 0 | Reput: 0 | ... |
AccountId: XXX | Class: Dobrodruh | Name: Kryploij3 | Level: 15 | Herolevel: 0 | Reput: 0 | ... |
AccountId: XXX | Class: Dobrodruh | Name: Grakonecek<3 | Level: 15 | Herolevel: 0 | Reput: 0 | ... |
The expected result that is shown in characterlist.php is
Position: 139 | Class: Dobrodruh | Name: Kryploij1 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 140 | Class: Dobrodruh | Name: Kryploid2 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 141 | Class: Dobrodruh | Name: Kryploij3 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 142 | Class: Dobrodruh | Name: Grakonecek<3 | Level: 15 | Herolevel: 0 | Reput: 0 |
But the bad result in userpanel.php is:
Position: 110 | Class: Dobrodruh | Name: Kryploij1 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 111 | Class: Dobrodruh | Name: Kryploid2 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 112 | Class: Dobrodruh | Name: Kryploij3 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 113 | Class: Dobrodruh | Name: Grakonecek<3 | Level: 15 | Herolevel: 0 | Reput: 0 |
Simply, my problem is in changed positions in userpanel. True positions are shown in characterlist. To calculate position according to ordering data in tables by Reputation I'm using row_number() function as is shown in my queries.
Your data has ties for reput and your row_number() expression is:
ROW_NUMBER() OVER (ORDER BY Reput DESC) AS row_number
Ordering in SQL is unstable. That means that rows with ties are in an arbitrary and indeterminate order -- and this order might change from one execution to the next.
Why is sorting unstable? Easy. SQL tables represent unordered sets, so there is no "underlying" ordering to define what happens in the case of ties.
The simple solution is to add another key. In your case, I think Name might be sufficient:
ROW_NUMBER() OVER (ORDER BY Reput DESC, Name) AS row_number
This is really hard to answer without sample data and inputs, but I think it is because the two queries do different things.
The first query paginates through the results, and the pagination imposes the ordering - presumably, $charlistpagemin and $charlistpagemax are 0 and 10 when you first load the page, so you get the first ten results.
The second query has not ordering - it's just a list of results, in undefined order.
If you add
order by Res.row_number desc
at the end of the query, it should work.

Postgresql join on array and transform to json

I would like to make a join on array containing ids and transform the result of this subselect into json (json array).
I have the following model:

The lnam_refs column contains identifiers that are related to the lnam column
I would like transform the column lnam_refs into something like [row_to_json(), row_to_json()] or [] or [row_to_json()] or …
I tried several methods but I can not achieve a clean result…
To try to be clearer :
Table in input:
id | label | lnam | lnam_refs
--------+----------------------+----------+-----------------------
1 | 'master1' | 11111111 | {33333333}
2 | 'master2' | 22222222 | {44444444,55555555}
3 | 'slave1' | 33333333 | {}
4 | 'slave2' | 44444444 | {}
5 | 'slave3' | 55555555 | {}
6 | 'master3' | 66666666 | {}
Results Expected:
id | label | lnam | lnam_refs | slaves
--------+----------------------+----------+-----------------------+---------------------------------
1 | 'master1' | 11111111 | {33333333} | [ {id: 3, label: 'slave1', lnam: 33333333, lnam_refs: []} ]
2 | 'master2' | 22222222 | {44444444,55555555} | [ {id: 4, label: 'slave2', lnam: 44444444, lnam_refs: []}, {id: 5, label: 'slave3', lnam: 55555555, lnam_refs: []} ]
6 | 'master3' | 66666666 | {} | []
Thanks for your help !
Here's one way to do it. (I created a table called t with that data you supplied.)
SELECT *, (SELECT JSON_AGG(ROW_TO_JSON(t2)) FROM t t2 WHERE label LIKE 'slave%' AND lnam = ANY(t1.lnam_refs)) AS slaves
FROM t t1
WHERE label LIKE 'master%'
I use the label field in the WHERE clause as I don't know how else you're determining which records should be master etc.
Result:
1;master1;11111111;{33333333};[{"id":3,"label":"slave1","lnam":33333333,"lnam_refs":[]}]
2;master2;22222222;{44444444,55555555};[{"id":4,"label":"slave2","lnam":44444444,"lnam_refs":[]}, {"id":5,"label":"slave3","lnam":55555555,"lnam_refs":[]}]
6;master3;66666666;{};

How to create hierarchal json object using ltree query results? (postgresql)

I'm trying to create a storage system for custom categories using postgres.
After looking around for potential solutions I settled on trying to use ltree;
Here is an example of raw data below;
+----+---------+---------------------------------+-----------+
| id | user_id | path | name |
+----+---------+---------------------------------+-----------+
| 1 | 1 | root.test | test |
| 2 | 1 | root.test.inbox | inbox |
| 3 | 1 | root.personal | personal |
| 4 | 1 | root.project | project |
| 5 | 1 | root.project.idea | idea |
| 6 | 1 | root.personal.events | events |
| 7 | 1 | root.personal.events.janaury | january |
| 8 | 1 | root.project.objective | objective |
| 9 | 1 | root.personal.events.february | february |
| 10 | 1 | root.project.objective.january | january |
| 11 | 1 | root.project.objective.february | february |
+----+---------+---------------------------------+-----------+
I thought that it might be easier to first order the results, and remove the top level from the path return. Using;
select id, name, subpath(path, 1) as path, nlevel(subpath(path, 1)) as level from testLtree order by level, path
I get;
+----+-----------+----------------------------+-------+
| id | name | path | level |
+----+-----------+----------------------------+-------+
| 3 | personal | personal | 1 |
| 4 | project | project | 1 |
| 1 | test | test | 1 |
| 6 | events | personal.events | 2 |
| 5 | idea | project.idea | 2 |
| 8 | objective | project.objective | 2 |
| 2 | inbox | test.inbox | 2 |
| 9 | february | personal.events.february | 3 |
| 7 | january | personal.events.january | 3 |
| 11 | february | project.objective.february | 3 |
| 10 | january | project.objective.january | 3 |
+----+-----------+----------------------------+-------+
I'm hoping to be able to transform this result into a set of JSON data somehow. I would like an output similar to this;
personal: {
id: 3,
name: 'personal',
children: {
events: {
id: 6,
name: 'events',
children: {
january: {
id: 7,
name: 'january',
children: null
},
february: {
id: 9,
name: 'february',
children: null
}
}
}
}
},
project: {
id: 4,
name: 'project',
children: {
idea: {
id: 5,
name: 'idea',
children: null
},
objective: {
id: 8,
name: 'objective',
children: {
january: {
id: 10,
name: 'january',
children: null
},
february: {
id: 11,
name: 'february',
children: null
}
}
}
}]
},
test: {
id: 1,
name: 'test',
children: {
inbox: {
id: 2,
name: 'inbox',
children: null
}
}
}
I've been looking around for the best way to do this but haven't came across any solutions that make sense to me. However, as I am new to postgres and SQL in general this is expected.
I think I may have to use a recursive query? I'm a bit confused over what the best method/execution of this would be. Any help/advice is much appreciated! and any further questions please ask.
I've put everything into a sqlfiddle below;
http://sqlfiddle.com/#!17/1713e/5
I ran into the same problem as you. I had a large struggle with this in PostgreSQL and it became overly complex to solve. Since I'm using Django (Python framework), I decided to solve it using Python. In case it can help anyone in my same situation, I would like to share the code:
https://gist.github.com/eherrerosj/4685e3dc843e94f3ef8645d31dbe490c