Basically, I wanted to get a response of user object and the response should also contain the subset followers list (from another table) of the user in a single query to the database.
user_table
-> id : user1
-> otheruserdata....
followers_table
-> user2 followed user1 (follower of user1)
-> user2 followed user3
-> user3 followed user1 (follower of user1)
Is this even possible or do I have to make two different queries one for the user and the other for his followers and merge it on the server ?
Response
user: {
userid: 1,
followers : [
user2 : {
user2 details...
},
....
]
}
What is the best way to do this ?
Related
I'm trying to build a user permissions structure in Postgres 11.5.
The basic idea is a user can belong to multiple groups and a group can have permissions for multiple applications. The user's permissions (if any) will override any permissions set at group level.
Permissions at user and usergroup level will be stored as json objects which I want to merge together with user permissions overwriting usergroup permissions if there is any overlap.
Example:
Brendan, James and n other users are in the exact same usergroups, but James should not be able to access app2.
Set up:
CREATE TABLE public.users
(
uid character varying COLLATE pg_catalog."default" NOT NULL,
ugid character varying[],
permissions json,
CONSTRAINT users_pkey PRIMARY KEY (uid)
);
INSERT INTO public.users VALUES
('brendan','{default,gisteam}','{}'),
('james','{default,gisteam}','{"app2":{"enabled":false}}');
CREATE TABLE public.usergroups
(
ugid character varying COLLATE pg_catalog."default" NOT NULL,
permissions json,
CONSTRAINT usergroups_pkey PRIMARY KEY (ugid)
);
INSERT INTO public.usergroups VALUES
('default','{"app1":{"enabled":true}}'),
('gisteam','{"app2":{"enabled":true},"app3":{"enabled":true}}');
Query:
SELECT uid, json_agg(permissions)
FROM (
SELECT
u.uid,
ug.permissions,
'group' AS type
FROM public.users u
JOIN public.usergroups ug
ON ug.ugid = ANY(u.ugid)
UNION ALL
SELECT
uid,
permissions,
'user' AS type
FROM public.users u2
) a
GROUP BY uid;
Actual query results:
+---------+----------------------------------------------------------------------------------------------------------+
| uid | final_permissions |
+---------+----------------------------------------------------------------------------------------------------------+
| brendan | [{"app1":{"enabled":true}},{"app2":{"enabled":true},"app3":{"enabled":true}},{}] |
| james | [{"app1":{"enabled":true}},{"app2":{"enabled":true},"app3":{"enabled":true}},{"app2":{"enabled":false}}] |
+---------+----------------------------------------------------------------------------------------------------------+
This kind of works, but I would want the object to be flattened and keys merged.
Desired result:
+---------+---------------------------------------------------------------------------+
| uid | final_permissions |
+---------+---------------------------------------------------------------------------+
| brendan | {"app1":{"enabled":true},"app2":{"enabled":true},"app3":{"enabled":true}} |
| james | {"app1":{"enabled":true},"app2":{"enabled":false},"app3":{"enabled":true}}|
+---------+---------------------------------------------------------------------------+
DB Fiddle: https://www.db-fiddle.com/f/9kb1v1T82YVxWERxnWLThL/3
Other info:
The actual permissions object set at usergroup level for each app will be more complex than in the example, e.g featureA is enabled, featureB is disabled etc and in fact more applications will be added in the future so I don't want to hardcode any references to specific apps or features if possible.
I suppose technically, if easier, the desired output would be the permissions object for just a single user so could replace the GROUP BY uid with a WHERE uid = 'x'
Question/Problem:
How can I modify the query to produce a flattened/merged permissions json object?
edit: fixed json
Your indicated desired output is not syntactically valid JSON. If I make a guess as to what you actually want, you can get it with jsonb_object_agg rather than jsonb_agg. You have to first unnest the values you select so that you can re-aggregate them together, which is done here by a lateral join against json_each:
select uid, jsonb_object_agg(key,value)
from (
SELECT
u.uid,
ug.permissions,
'group' AS type
FROM public.users u
JOIN public.usergroups ug
ON ug.ugid = ANY(u.ugid)
UNION ALL
SELECT
uid,
permissions,
'user' AS type
FROM public.users u2) a
CROSS JOIN LATERAL json_each(permissions)
GROUP BY uid;
Yields:
uid | jsonb_object_agg
---------+------------------------------------------------------------------------------------
brendan | {"app1": {"enabled": true}, "app2": {"enabled": true}, "app3": {"enabled": true}}
james | {"app1": {"enabled": true}, "app2": {"enabled": false}, "app3": {"enabled": true}}
Your select of "group" as type is confusing as it is never used.
I am new here and with PHP/MySQL programming. I need do the next consult in my database.
I have two tables:
-The first of relations between users where friends have the value "2"
The columns is like:
id | Username1 | username2 | relation
-The seconds is for messages post by users
The columns is like:
id | username | message
The id is the "primary key" with auto increment property. (in both)
I want to show all message of friends of one user by order of post (Most recently first)
So I need select the max value id where the user1 and user2 is friends, but I need select the max value of "messages table" and check if they are friends in the "relations table"
I know what the next is not the syntax but I need something like this:
SELECT message
FROM message_table
WHERE MAX(id) AND ( FROM relations
WHERE ( ( user1="randomuser"
OR user2="randomuser")
AND relation="2")
)
ORDER BY id DESC
I know what that is wrong... but I need that two filters to show all friend message in posting order.. So how can I show register from one table with a one condition in that table and the second condition in other table.
Edit: Example:
id | Username1 | username2 | relation
1 Randomuser1 Randomuser2 2
2 Randomuser1 Randomuser3 0
3 Randomuser1 Randomuser5 2
id | Username | message
1 Randomuser1 Hi this is a random message?
2 Randomuser2 I don"t like your message
3 Randomuser5 Sure, is a bad message
So I want to show all message of friends of randomuser1 by order of posting
First the user"s friends of Randomuser1 is
Randomuser2 and Randomuser5 (The "2" Mean they are friends)
so i want to show all messages of their friends by order of posting (By id order of second table (message_table))
So i need a output like:
id | Username | message
3 Randomuser5 Sure, is a bad message
2 Randomuser2 I don"t like your message
That is the output what I need when I choose the messages of friends of user Randomuser1
I'm having trouble wrapping my head around an SQL query, trying to figure out something.
Just quickly, here is my (simple) table:
It's a representation of friends added in a social network site.
I have to use the table format like this, user1 and user2 are both primary keys.
User1 | User2
--------------------------------------
foo#a.com | things#stuff.com
foo#a.com | lala#hi.com
things#stuff.com| lol#k.com
lol#k.com | foo#a.com
foo#a.com | lol#k.com
What I need to do is write a SELECT statement that will return all unique users that are friends with foo#a.com for example.
SELECT User2
FROM members
WHERE User1 = 'things#stuff.com'
Would return lol#k.com and not foo#a.com, even though I need it to return the latter.
SELECT *
FROM members
WHERE User1 = 'foo#a.com'
OR User2 = 'foo#a.com'
Would return an error I think? Something with selecting multiple columns probably.
So I figure a union join or some other join is necessary (union so no duplicates?) but I'm really not sure how to go about doing it.
I'm trying to implement this in PHP, so even if the last query I wrote worked, I'm not sure how to echo User1 or User2 depending on which it returned/which one I needed if that makes sense.
Using a UNION (for performance) :-
SELECT User2
FROM members
WHERE User1 = 'foo#a.com'
UNION
SELECT User1
FROM members
WHERE User2 = 'foo#a.com'
Use an alias name for the column
SELECT User2 AS friend
FROM members
WHERE User1 = 'things#stuff.com'
UNION
SELECT User1 AS friend
FROM members
WHERE User2 = 'things#stuff.com'
Now you can echo friend.
HTH
It all depends on how you define the relationship between the two users.
For example, you have a table entry where User1 = 'foo#a.com' and User2='mumu#f.com'. What does it mean? Does it mean that user foo became friends with mumu? Does it matter the direction of the 'friendship'?
If the answer is no an you simply want to fetch all rows where either user is foo, then your query
SELECT *
FROM members
WHERE User1 = 'foo#a.com'
OR User2 = 'foo#a.com'
is correct.
However, to fetch the data you need to explore both columns for results.
I have a MySQL table with two copies (one in local server, one in web host) and I want to update some fields in my local server, than update only those values in my web host.
So say my table is like
Table in localhost, initially :
id username money
---- ---------- -------
1 user_01 0
2 user2 0
Table in web host, initially :
id username money
---- ---------- -------
1 user_01 1000
2 user2 2000
Than I want to change the username user_01 to user1, and update the web database, but not change the money field
Table in localhost, after change :
id username money
---- ---------- -------
1 user1 0
2 user2 0
&
query -> ????
Table I want in web server, after change :
id username money
---- ---------- -------
1 user1 1000
2 user2 2000
I tried to delete the table and create it from scratch but then the money value becomes 0, which I want to avoid.
So what query / type of export should I use (in phpMyAdmin or whatever) to update only certain fields?
Thanks !
Isn't it like this?
UPDATE localhost
SET username = 'user'
WHERE username = 'user_01'
OR
UPDATE localhost
SET username = REPLACE(username, '_0', '')
WHERE username LIKE '%\_0%'
expr LIKE pat [ESCAPE 'escape_char']
I am using SSRS Report Builder.
My query returns permits for each user:
user1 permit1
user1 permit2
user1 permit3
user2 permit2
user2 permit4
...
How can I create a report like this?
USER PERMITS
------------------------------------
user1 permit1 permit2 permit3
user2 permit2 permit4
...
Or even better:
USER PERMIT1 PERMIT2 PERMIT3 PERMIT4
-----------------------------------------------
user1 x x x
user2 x x
...
The difficulty is that the column "Permit" is not a group of set values. We will add new permits and remove frequently.
Thanks for any assistance.
You're looking for the Matrix Control. In this control you'll group rows on the first (user) column, and group columns on the second (permit) column. In the cell you can check the value of the permit, and if it's set you plot an 'x'. Schematically the control will look like this:
---------+-----------------------------------------------
| | [Permit] |
|---------+-----------------------------------------------
| [User] | =Iif(Fields!Permit.Value Is Nothing, "", "x") |
---------+-----------------------------------------------