I
I
Igor Tikhonov2019-11-23 15:23:43
PostgreSQL
Igor Tikhonov, 2019-11-23 15:23:43

How to correctly get data from two tables in one row?

Hello. I've been struggling with a simple question for several days now, I can't find an answer on the Internet (I don't know what wording to use to find the right one).
There are two PostgreSQL tables:
users - list of users

  • id
  • email
  • name

socials - list of attached social networks to all users. Selected compare users.id = socials.user_id
  • social_id
  • user_id
  • type
  • token

You need to display user data, including all attached social networks.
A user can have multiple social networks attached.
If you make a request like this:
select "users"."id", "users"."name", "socc_acc"."type", "socc_acc"."token" from "users" left join (select "social_id", "user_id", "type", "token" from "socials" where "user_id" = 100) as "socc_acc" on "socc_acc"."user_id" = "users"."id" where "id" = 100 group by "socc_acc"."social_id", "users"."id"

100 - id of the selected user;
in the presence of several social networks, the result is the following:
[{
    id: 100,
    name: 'Haylee Simonis',
    type: 1,
 token: 'something'
  },
  {
    id: 100,
    name: 'Haylee Simonis',
    type: 2,
 token: 'something2'
  }]

those. returns two strings filled with the same, the differences are only in the fields type and token.
Is there a way to output all data in one line without duplicate user data?
Tried the join method with the ARRAY_AGG function:
select "0"."id", "0"."email", "0"."name, ARRAY_AGG("1"."type") as social_type, ARRAY_AGG("1"."token") as social_token from "users" as "0", "socials" as "1" where "0"."id" = 100 and "1"."user_id" = 100 group by "0"."id"

in this case, the result is closer to what we would like to see:
[{
    id: 100,
    email: '[email protected]',
    name: 'Haylee Simonis',
    social_type: [ 2, 1 ],
    social_token: [ 'something2', 'something' ]
  }]

But maybe there is a better way to do something like this:
[{
    id: 100,
    email: '[email protected]',
    name: 'Haylee Simonis',
    socials: [{
 type: 1,
token: 'something'
 },
{
type: 2,
token: 'something2'
}]
  }]

Working in Node.js (Koa) with Knex if that matters.
Thank you in advance for your help.
I would also be grateful if you could suggest a current book or article that explains such basics.
PS I haven't dealt with SQL before so maybe I'm approaching the question in the wrong way.
Perhaps it is worth doing two different, unrelated queries?
UPD Was able to find a solution like this:
SELECT "social_id", array_agg('[' || type || ',' || token || ']') AS "socials" FROM "socials" WHERE "user_id" = 105 GROUP BY "social_id";

result:
socials: [
      '[2,something2]',
      '[1,something]'
    ]

Even better, but the query syntax doesn't look very good. Perhaps there is a more elegant solution?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
I
Igor Tikhonov, 2019-11-24
@IgorT

After three days of searching, I finally came up with this solution, maybe it will be useful to someone:
json_build_object takes as arguments the name of the key for the object and the value (the name of the key in the table) separated by commas.
Result:

[
 { type: 2, token: 'something2' },
 { type: 1, token: 'something' }
]

It remains only to combine with the request above so that social networks are displayed in this way when requesting user data.
It is important to include all keys from the user table in the ORDER BY, otherwise duplication will start again.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question