I have SQL this query:
SELECT f.follower_id, u.fname, u.lname
FROM followers f
INNER JOIN users u ON f.follower_id = u.id
WHERE f.user_id = $user_id
AND u.status = 1
ORDER BY fname, lname
LIMIT 10
I have two models: User and Follower.
A user can have many followers, and each follower has its own user data. I want to be able to get all of a user's followers (who have a status of 1) by doing something like this:
$followers = User::get_followers();
Add this to your User model:
public function followers()
{
return $this->belongsToMany(User::class, 'followers', 'user_id', 'follower_id')
->where('status', 1)
->orderBy('fname')
->orderBy('lname');
}
Then you can access them like this:
$followers = $user->followers;
Related
I'm trying to get a list in a linq with joins and get all events for specific user.
This is the query I have so far:
var runnerObject = from r in _context.Runners
join re in _context.RunnerEvents
on r.RunnerId equals re.RunnerId
join e in _context.Events
on re.EventId equals e.EventId
where r.RunnerId == runnerId
select new RunnerVM
{
RunnerId = r.RunnerId,
FirstName = r.FirstName,
LastName = r.LastName,
UserId = r.UserId,
Events = //get all events in Events table for the runnerId
};
Events should be all entries from Events table for that runner, based on their id which is joined in the RunnerEvents table. How can I get that?
Something like this?
var runnerObject = from r in _context.Runners
join re in _context.RunnerEvents
on r.RunnerId equals re.RunnerId
join e in _context.Events
on re.EventId equals e.EventId
where r.RunnerId == runnerId
select new RunnerVM
{
RunnerId = r.RunnerId,
FirstName = r.FirstName,
LastName = r.LastName,
UserId = r.UserId,
Events = r.Events.Select(e => new Event { }).ToList()
};
I have an Express API using Postgres via Knex and Objection.
I want to set up a Model method or scope that returns an array of Parent model instances in order of number of associated Children.
I have looked through the Knex an Objection docs
I have seen the following SQL query that will fit, but trying to figure out how to do this in Knex:
SELECT SUM(O.TotalPrice), C.FirstName, C.LastName
FROM [Order] O JOIN Customer C
ON O.CustomerId = C.Id
GROUP BY C.FirstName, C.LastName
ORDER BY SUM(O.TotalPrice) DESC
This is how it should be done with knex (https://runkit.com/embed/rj4e0eo1d27f):
function sum(colName) {
return knex.raw('SUM(??)', [colName]);
}
knex('Order as O')
.select(sum('O.TotalPrice'), 'C.FirstName', 'C.LastName')
.join('Customer C', 'O.CustomerId', 'C.Id')
.groupBy('C.FirstName', 'C.LastName')
.orderBy(sum('O.TotalPrice'), 'desc')
// Outputs:
// select SUM("O"."TotalPrice"), "C"."FirstName", "C"."LastName"
// from "Order" as "O"
// inner join "Customer C" on "O"."CustomerId" = "C"."Id"
// group by "C"."FirstName", "C"."LastName"
// order by SUM("O"."TotalPrice") desc
But if you are really using objection.js then you should setup models for your Order and Customer tables and do something like this:
await Order.query()
.select(sum('TotalPrice'), 'c.FirstName', 'c.LastName')
.joinRelated('customer as c')
.groupBy('c.FirstName', 'c.LastName')
.orderBy(sum('TotalPrice'), 'desc')
In case anyone is interested, I just included the raw SQL query as follows:
router.get('/leaderboard', async (req, res) => {
let results = await knex.raw('SELECT users_id, username, COUNT(acts.id) FROM acts INNER JOIN users ON acts.users_id = users.id GROUP BY users_id, username ORDER BY COUNT(acts.id) DESC');
console.log(results);
res.json(results.rows);
});
Given a table of players (users) with several fields. One of this is their rating with respect other players.
I'd like to implement via LINQ following SQL query:
SELECT p.*,
(select COUNT(*) from Users where (Rating > p.Rating)) as Rank
FROM Users as p
ORDER BY p.Rating DESC
In other words, last field (RANK) should give the rank of each user with respect the others:
Id Username ... Rating Rank
43 player41 ... 1002,333 0
99 player97 ... 1002 1
202 player200 ... 1002 1
53 player51 ... 1000,667 2
168 player166 ... 1000,667 2
56 player54 ... 1000 3
32 player30 ... 999,342 4
This attempt does not work:
var q = from u in Users
orderby u.Rating descending
group u by u.Id into g
select new
{
MyKey = g.Key,
User = g.First(),
cnt = Users.Count(uu => uu.Rating > g.First().Rating) + 1
};
Just for your knowledge, note that the table Users is mapped to a EF entity named User with a 'NotMapped' int? field named Rank where I'd like to manually copy the rank:
class User {
...
[NotMapped]
public virtual int? Rank { get; internal set; }
}
You'll want something like:
var rankedUsers = db.Users
.Select(user => new
{
User = user,
Rank = db.Users.Count(innerQueryUser => innerQueryUser.Rating > user.Rating)
})
.ToList();
Which will give you a list of users and their Rank as an anonymous type.
You'll then be able to do something like:
List<User> users = rankedUsers.Select(rankedUser=>
{
rankedUser.User.Rank = rankedUser.Rank;
return rankedUser.User;
})
.ToList();
Try this:
var q = (from u in Users
select new
{
UserId = u.Id,
UserObj = u,
Rank = (from u1 in Users where u1.Rating>u.Rating select u1).Count()
}).ToList();
I have a Users with friends:
User {
"#rid:": "#11:2"
...
friends: ["#61:1", "#61:2", "#61:3"]
}
...
User {
"#rid:": "#11:3"
...
friends: ["#61:2", "#61:3","#61:4"]
}
How i can to find joint friends of users ("#11:2", "#11:3") with osql?
So query should return "#61:2", "#61:3".
Try this:
select from User where #rid in (select out() from User where #rid = "#11:2") and #rid in (select out() from User where #rid = "#11:3")
Hope it helps
Regards
A bit rusty on LINQ
I want to get a single result from related tables for a given user. See schema below.
Each user has one or more roles. I want a list of usernames and a custom string that is a list of their roles in a format such as "Role1 - Role2 - Role3", where the values are the RoleNames associated with the UserRole/Role for that user.
Role
=====
RoleId
RoleCode
RoleName
UserRole
========
UserRoleId
RoleId
UserId
Users
======
UserId
UserName
Testing it out in LINQpad, I can get a list of usernames and their roles, but instead of the RoleName, I want a single field in the result to be a formatted string of ALL the users roles, as mentioned above.
Here is what I have now. How can I construct a list of the roles for each user?
from u in Users
join ur in UserRoles on u.UserId equals ur.UserKey
join r in Roles on ur.RoleKey equals r.RoleId
select new {
u.UserId,
u.UserName,
r.RoleName
}
Add group by UserName to your LINQ query, and use string.Join to format the roles separated by "-".
You can test this in LINQPad -
var Roles = new [] {new{RoleId=1,RoleCode="SU",RoleName="Super User"},new{RoleId=2,RoleCode="PU",RoleName="Power User"}};
var Users = new [] {new{UserId=1,UserName="Bit Shift"},new{UserId=2,UserName="Edward"}};
var UserRoles = new [] {new{UserRoleId=1,RoleId=1,UserId=1},new{UserRoleId=2,RoleId=2,UserId=1},new{UserRoleId=3,RoleId=2,UserId=2}};
var userRoles = from u in Users
join ur in UserRoles on u.UserId equals ur.UserId
join r in Roles on ur.RoleId equals r.RoleId
select new
{
u.UserId,
u.UserName,
r.RoleName
}
into userRole
group userRole by userRole.UserName into userGroups
select new{ UserName=userGroups.Key, Roles = string.Join(" - ", userGroups.Select(ug => ug.RoleName))};
userRoles.Dump();
More succinct version, which includes UserId+UserName in result -
var userRoles = from u in Users
join ur in UserRoles on u.UserId equals ur.UserId
join r in Roles on ur.RoleId equals r.RoleId
group r by u into userGroups
select new{ User=userGroups.Key, Roles = string.Join(" - ", userGroups.Select(r => r.RoleName))};
userRoles.Dump();
When executing against SQL database, you need to the query split into two parts, as String.Join is not supported by LINQ to SQL, like this -
var userRoleGroups = (from u in Users
join ur in UserRoles on u.UserId equals ur.UserId
join r in Roles on ur.RoleId equals r.RoleId
group r by u into userGroups select userGroups)
.ToList(); // This causes SQL to be generated and executed
var userRoles = from userGroups in userRoleGroups select(new{ User=userGroups.Key, Roles = string.Join(" - ", userGroups.Select(r => r.RoleName))});
userRoles.Dump();
Or try using Aggregate instead of String.Join, as you suggested, like this -
var userRoles = from u in Users
join ur in UserRoles on u.UserId equals ur.UserId
join r in Roles on ur.RoleId equals r.RoleId
group r by u into userGroups
select(new{
User=userGroups.Key,
Roles = userGroups.Select(s => s.RoleName).Aggregate((current, next) => current + " - " + next)});
userRoles.Dump();
Group the RoleNames over the UserNames and use String.Join to get the desired result.
from u in Users
join ur in UserRoles on u.UserId equals ur.UserKey
join r in Roles on ur.RoleKey equals r.RoleId
group r.RoleName by u.UserName into grp
select new {
UserName = grp.Key,
Roles = String.Join(" - ", grp)
};
This will not return the UserIds. If they're important for the result, you need to change the code to
.... join as above
group r.RoleName by new {u.UserId, u.UserName} into grp
select new {
grp.Key.UserName,
grp.Key.UserId,
Roles = String.Join(" - ", grp)
};
This will create a grouping key containing both UserId and UserName, so you have that available in your select.