TypeORM / Postgres - Include all in relation where at least one meets requirement - postgresql

I am very new to SQL/TypeORM in general and I'm currently facing a problem where I want to load match participants related to a match where at least one participant has a passed userId. The query could be thought of as "Load all my matches with my opponents". I have three tables:
public.match << OneToMany >> public.match_participant << ManyToOne >> public.user
So far I have gone about doing:
select * from public.match m
left join public.match_participant mp on mp."matchId" = m.id
left join public.user u on u.id = mp."userId"
where u.id = 3
and in typeORM
repository
.createQueryBuilder('match')
.leftJoinAndSelect('match.participants', 'participants')
.leftJoinAndSelect('participants.user', 'user')
.where('user.id=:id')
.setParameter('id', 1)
.getMany();
Which of course loads all matches, participants and users for that particular userId but other participants are not included. I believe something like a "subquery" could be of use but I can't seem to figure it out.
Any help is greatly appreciated!
Thanks in advance.

After a bunch of trial and error I learned how to convert a pure query to the builder. The solution was the following:
matchRepository
.createQueryBuilder('match')
.innerJoin(
query => {
return query
.from(MatchParticipant, 'p')
.select('p."matchId"')
.where('p."userId" = :id');
},
'selfMatch',
'"selfMatch"."matchId" = match.id',
)
.leftJoinAndSelect('match.participants', 'participants')
.leftJoinAndSelect('participants.user', 'user')
.setParameter('id', id)
.getMany();

I don't think you even need the query builder for this.
#Entity()
class Match {
#OneToMany(...)
participants: MatchParticipant[];
}
#Entity()
class MatchParticipant {
#ManyToOne(...)
match: Match;
#ManyToOne(...)
participant: Participant;
}
#Entity()
class User {
#OneToMany(...)
matches: MatchParticipant[];
}
// ...
repository.manager.find(MatchParticipant, { where: { match: { participants: { participant: { id } } } } });

Related

How to get data sorted with relation using TypeORM?

I want to get user data with relation sorted but with this code it just sort the user but I want to sort data that have relation with user I'm using eager, could any one help me ?
getUerWithId(pramas: string): Observable<userEntity[]> {
return from(this.userRepository.find({
where: [
{ id: pramas }
],
order:{
id:'DESC'
}
}))
}
With the repository, I don't know if it is possible, but you can try with query builder to get ordered relations. Follow example bellow:
this.userRepository.createQueryBuilder()
.innerJoinAndSelect("User.notification", "Notification")
.orderBy({'Notification.createdAt': 'DESC'})
.where("User.id = :id", {
id: Number(id),
})
.getOne();
Remember to put the right relationship for your entity, and right names for your properties.

Laravel Eloquent Many-To-Many Query Producing Extra null WHERE clause

I'm using Eloquent to produce results from a query comprised of three tables:
photos (id)
photos_to_photosets (photo_id, photoset_id)
photosets (id)
My models have their many-to-many relationships defined as:
class Photo extends Model
{
public function photosets()
{
return $this->hasMany(PhotoSet::class, 'photos_to_photo_sets');
}
}
And
class PhotoSets extends Model
{
public function photos()
{
return $this->belongsToMany(Photo::class, 'photos_to_photo_sets');
}
}
Now, to fetch results I'm forced to use the following Eloquent code:
$photoData = $this->photoSets->photos()
->orWhere('photo_set_id', '=', $id)
->get();
This produces the following query:
SELECT * FROM `photos`
INNER JOIN `photos_to_photo_sets`
ON `photos`.`id` = `photos_to_photo_sets`.`photo_id`
WHERE `photos_to_photo_sets`.`photo_set_id` is null
OR `photo_set_id` = ?
This query works, but I can't seem to remove WHERE `photos_to_photo_sets`.`photo_set_id` is null from the query.
I've tried to just use ->where('photo_set_id', '=', $id) but the null clause still remains; even worse it produces the following WHERE clause:
... WHERE `photos_to_photo_sets`.`photo_set_id` IS NULL
AND `photo_set_id` = ?
Is there any way, utilizing Eloquent, to remove this null WHERE clause segment?
Ideally, I'd like to end up with the following query:
SELECT * FROM `photos`
INNER JOIN `photos_to_photo_sets`
ON `photos`.`id` = `photos_to_photo_sets`.`photo_id`
WHERE `photo_set_id` = ?
Thank you in advance for any help!
UPDATE
Based off #Jonas Staudenmeir's answer, the null WHERE clause has been removed.
To achieve this, I set the photoSet's model ID prior to running the query. The resulting code was:
$this->photoSets->id = $photoset_id;
$photoData = $this->photoSets->photos()->get();
Which produced:
SELECT * FROM `photos`
INNER JOIN `photos_to_photo_sets`
ON `photos`.`id` = `photos_to_photo_sets`.`photo_id`
WHERE `photo_set_id` = ?
The injected model doesn't have an id:
$this->photoSet->id = $id;
Then you don't need the additional constraint:
$photoData = $this->photoSets->photos;

Sequelize bulk update with inner join

I am currently working with Sequelize and can not figure out how to update bulk when im associating two tables together. I have the follow:
Tables:
members
user_id
channel_id
all
activities
user_id
channel_id
I am trying to update members.all when the user_ids match, members.channel_id is 2 and activities.channel_id is not 2.
Here is working Postgresql:
UPDATE members AS m
SET "all" = true
FROM activities AS a
WHERE m.user_id = a.user_id
AND m.channel_id = 2
AND a.current_channel != 2;
Is this possible to do is sequelize? How do include a.current_channel != 2 into my current update?
Member.update(
{ all: true },
{ where: { channel_id: channelId } },
)
When I try to add an include it does not work.
I think you can't do something like that using Sequelize update method. I would use the include option in a findAll method, but as far as I can see on the documentation, there is no include option for the update method.
You could use a raw query to use directly the query.
sequelize.query("UPDATE members AS m SET "all" = true FROM activities AS a WHERE m.user_id = a.user_id AND m.channel_id = 2 AND a.current_channel != 2").spread((results, metadata) => {
// Results will be an empty array and metadata will contain the number of affected rows.
});
Generally, i use this hack
models.findAll({
where: {
// which models to update
}
}).then(targets => {
models.target.update({
// your updates
},{
where : {
target_primary_key: targets.map(t => t.primary_key)
}
})
})

How to query all the owned objects in one query MTM?

I have a list of the owning side of a many-to-many relationship. How do I query all the owned objects in one query using Grails GORM? In SQL I would used the join table and the owned table and the ids for the owning table with an in clause.
Example domain classes:
class Book {
static belongsTo = Author
static hasMany = [authors:Author]
String title
}
class Author {
static hasMany = [books:Book]
String name
}
So I have a List or Set of Authors and I want to find all their Books in one query.
select b.*
from book b
join author_book ab on b.id = ab.book_id
where ab.author_id in (1, 2, 3);
In Grails I tried the following but it fails.
def books = Book.withCriteria {
inList('authors', authors)
}
You need to join the author first:
def books = Book.withCriteria {
authors {
inList('id', authors*.id)
}
}
Is this what you're looking for?
Book.findAllByAuthorInList(authors)

Distinct and group by at the same time in LINQ?

Let say I have the following classes:
Product { ID, Name }
Meta { ID, Object, Key, Value }
Category { ID, Name }
Relation {ID, ChildID, ParentID } (Child = Product, Parent = Category)
and some sample data:
Product:
ID Name
1 Chair
2 Table
Meta
ID Object Key Value
1 1 Color "Red"
2 1 Size "Large"
3 2 Color "Blue"
4 2 Size "Small"
Category
ID Name
1 Indoor
2 Outdoor
Relation
ID ChildID ParentID
1 1 1
2 1 2
3 2 1
Can we use Distinct and Group by to produce the following format (ProductDetail)
ID=1,
Name=Chair,
Parent=
{
{ ID=1, Name="Indoor" },
{ ID=2, Name="Outdoor" }
},
Properties { Color="Red", Size="Large" }
ID=2,
Name=Table,
Parent=
{
{ ID=1, Name="Indoor"}
},
Properties { Color = "Blue", Size = "Small" }
which we can get the "Color" value of the first item by using
ProductDetails[0].Properties.Color
Any helps would be appreciated!
No, you can't do this based on what you've said - because "Color" and "Size" are part of the data, rather than part of the model. They're only known at execution time, so unless you use dynamic typing, you're not going to be able to access it by Properties.Color.
You could, however, use Properties["Color"] potentially:
var query = from product in db.Products
join meta in db.Meta
on product.ID equals meta.Object
into properties
select new { Product = product,
Properties = properties.ToDictionary(m => m.Key,
m => m.Value) };
So for each product, you'll have a dictionary of properties. That works logically, but you may need to tweak it to get it to work in the entity framework - I don't know how well that supports ToDictionary.
EDIT: Okay, I'll leave the above up as the "ideal" solution, but if EF doesn't support ToDictionary, you'd have to do that part in-process:
var query = (from product in db.Products
join meta in db.Meta
on product.ID equals meta.Object
into properties
select new { product, properties })
.AsEnumerable()
.Select(p => new {
Product = p.product,
Properties = p.properties.ToDictionary(m => m.Key,
m => m.Value) });
I just came across this question while learning LINQ, but I wasn't satisfied that Jon's output matched the question (sorry Jon). The following code returns a List of anonymously-typed objects that better match the structure of your question:
var ProductDetails = (from p in Product
let Parents = from r in Relation
where r.ChildID == p.ID
join c in Category on r.ParentID equals c.ID
into RelationCategory
from rc in RelationCategory
select new
{
rc.ID,
rc.Name
}
join m in Meta on p.ID equals m.Object into ProductMeta
select new
{
p.ID,
p.Name,
Parent = Parents.ToList(),
ProductMeta
})
.AsEnumerable()
.Select(p => new
{
p.ID,
p.Name,
p.Parent,
Properties = p.ProductMeta
.ToDictionary(e => e.Key, e => e.Value)
}).ToList();
Credit goes mostly to Jon Skeet and the Visual Studio debugger ;)
I realise that you've probably moved on by now but hopefully this might help someone else looking to learn LINQ, as I was.