【问题标题】:Select specific columns from jeft join query, TypeORM从 jeft 连接查询中选择特定列,TypeORM
【发布时间】:2022-04-26 13:13:25
【问题描述】:

我的任务是获取有关数据库中用户的关键信息。有很多left joins 并且查询工作很慢。 我试图以某种方式优化它,我决定只选择特定的字段(目前只有记录的 id)。

这是我的查询的一部分。我只需要获取属于用户的每个事件的 id,并对数据库中的每个用户执行相同的操作。理想情况下,我应该得到一组 id。

我尝试构建一个子查询,但找不到一些带有解释的示例。官方文档中的一个例子对我来说还不够。

当我运行它时,我得到了错误

syntax error at or near "SELECT"
QueryFailedError: syntax error at or near "SELECT"
this.createQueryBuilder('profile')
            .leftJoinAndSelect('profile.avatarPhoto', 'avatarPhoto')
            .leftJoinAndSelect('profile.coverPhoto', 'coverPhoto')
            .leftJoinAndSelect('profile.primaryCountry', 'country')
            .leftJoinAndSelect('profile.primaryCity', 'city')
            .leftJoinAndSelect('profile.images', 'image')
            .leftJoinAndSelect('profile.practicedSports', 'practicedSport')
            .leftJoinAndSelect(
                (subQuery) =>
                    subQuery
                        .subQuery()
                        .createQueryBuilder()
                        .select(['id'])
                        .leftJoin('user', 'user')
                        .from(SportEvent, 'event'),
                'event',
                'event.user.id = profile.id',
            )
            // .leftJoinAndSelect('profile.sportServices', 'service')
            // .leftJoinAndSelect('profile.lessons', 'lesson')
            // .leftJoinAndSelect('profile.activityRequests', 'request')
            .leftJoin('profile.userAuth', 'auth')
            .where('auth.registered = true')
            .andWhere('auth.blocked = false')
            .take(params.pageSize)
            .skip(itemsNumber)
            .getMany()

这是生成的SQL代码

SELECT DISTINCT "distinctAlias"."profile_id" as "ids_profile_id" 
FROM (SELECT "profile"."id" AS "profile_id", "profile"."email" AS "profile_email", 
"profile"."first_name" AS "profile_first_name", 
"profile"."middle_name" AS "profile_middle_name", 
"profile"."last_name" AS "profile_last_name", 
"profile"."about_user" AS "profile_about_user", 
"profile"."interests" AS "profile_interests", 
"profile"."birthday" AS "profile_birthday", 
"profile"."gender" AS "profile_gender", 
"profile"."sport_level" AS "profile_sport_level", 
"profile"."phone_number" AS "profile_phone_number", 
"profile"."contacts" AS "profile_contacts", 
"profile"."payment_methods" AS "profile_payment_methods", 
"profile"."settings" AS "profile_settings", 
"profile"."options" AS "profile_options", 
"profile"."updated_at" AS "profile_updated_at", 
"profile"."created_at" AS "profile_created_at", 
"profile"."avatar_photo_id" AS "profile_avatar_photo_id", 
"profile"."cover_photo_id" AS "profile_cover_photo_id", 
"profile"."cover_video_id" AS "profile_cover_video_id", 
"profile"."default_album_id" AS "profile_default_album_id", 
"profile"."primary_country_id" AS "profile_primary_country_id", 
"profile"."primary_city_id" AS "profile_primary_city_id", 
"profile"."primary_language_id" AS "profile_primary_language_id", 
"avatarPhoto"."id" AS "avatarPhoto_id", 
"avatarPhoto"."name" AS "avatarPhoto_name", 
"avatarPhoto"."image_paths" AS "avatarPhoto_image_paths", 
"avatarPhoto"."updated_at" AS "avatarPhoto_updated_at", 
"avatarPhoto"."created_at" AS "avatarPhoto_created_at", 
"avatarPhoto"."album_id" AS "avatarPhoto_album_id", 
"avatarPhoto"."user_id" AS "avatarPhoto_user_id", 
"coverPhoto"."id" AS "coverPhoto_id", 
"coverPhoto"."name" AS "coverPhoto_name", 
"coverPhoto"."image_paths" AS "coverPhoto_image_paths", 
"coverPhoto"."updated_at" AS "coverPhoto_updated_at", 
"coverPhoto"."created_at" AS "coverPhoto_created_at", 
"coverPhoto"."album_id" AS "coverPhoto_album_id", 
"coverPhoto"."user_id" AS "coverPhoto_user_id", 
"country"."id" AS "country_id", 
"country"."name" AS "country_name", 
"country"."alpha_2" AS "country_alpha_2", 
"country"."alpha_3" AS "country_alpha_3", 
"country"."calling_code" AS "country_calling_code", 
"country"."enabled" AS "country_enabled", 
"country"."top" AS "country_top", "city"."id" AS "city_id", 
"city"."name" AS "city_name", 
"city"."coordinates" AS "city_coordinates", 
"city"."top" AS "city_top", 
"city"."country_id" AS "city_country_id", 
"image"."id" AS "image_id", 
"image"."name" AS "image_name", 
"image"."image_paths" AS "image_image_paths", 
"image"."updated_at" AS "image_updated_at", 
"image"."created_at" AS "image_created_at", 
"image"."album_id" AS "image_album_id", 
"image"."user_id" AS "image_user_id", 
"practicedSport"."id" AS "practicedSport_id", 
"practicedSport"."start_date" AS "practicedSport_start_date", 
"practicedSport"."sport_id" AS "practicedSport_sport_id", 
"practicedSport"."user_id" AS "practicedSport_user_id", 
"event".* 
FROM "user_profiles" "profile" LEFT JOIN "media_images" "avatarPhoto" 
ON "avatarPhoto"."id"="profile"."avatar_photo_id"  LEFT JOIN "media_images" "coverPhoto" 
ON "coverPhoto"."id"="profile"."cover_photo_id"  LEFT JOIN "data_countries" "country" 
ON "country"."id"="profile"."primary_country_id"  LEFT JOIN "data_cities" "city" 
ON "city"."id"="profile"."primary_city_id"  LEFT JOIN "media_images" "image" 
ON "image"."user_id"="profile"."id"  LEFT JOIN "user_practiced_sports" "practicedSport" 
ON "practicedSport"."user_id"="profile"."id"  
LEFT JOIN SELECT id FROM "sport_events" "event" 
LEFT JOIN "user" "user" "event" 
ON event.user.id = "profile"."id"  
LEFT JOIN "user_auth" "auth" 
ON "auth"."profile_id"="profile"."id" 
WHERE "auth"."registered" = true 
AND auth.blocked = false) "distinctAlias" 
ORDER BY "profile_id" ASC LIMIT 15

您能否解释一下我做错了什么,或者给我发一篇带有解释的文章? 谢谢!

【问题讨论】:

    标签: node.js postgresql nestjs typeorm


    【解决方案1】:

    我认为不可能加入event.user.id 你应该把它分成两个leftJoins。还要确保使用leftJoin(..)(然后通过.select(..).addSelect(..) 指定要选择的字段)而不是leftJoinAndSelect(..),因为这会自动选择所有字段。

    【讨论】:

    • 这个答案几乎很棒,但缺点是这需要一个 .getRawOne 或 .getRawMany ,它不提供解析的实体,而是一个简单的 JSON。或者至少,不适合我。
    • 我认为如果将其拆分为两个leftJoin(..) TypeORM 将返回的行转换为实体应该仍然没有问题!我不认为getRaw..(..)是必要的!
    • 请附上一个例子来改进你的答案。
    【解决方案2】:

    如果你想通过 TypeOrm 使用 join,你可以使用 .leftjoin() 代替 leftjoinandSelect()

    这里是例子,我用node和typeorm做了一个献血api的例子

    //BLOODDONATION.ts
    
    import { Column, Entity,PrimaryColumn } from "typeorm";
    
    @Entity('blood_donation')
    export class BloodDonation
    {
        
        @PrimaryColumn()
        id:number;
    
        @Column()
        donor_id:number;
    
        @Column()
        doctor_id:number;
    
        @Column()
        quantity:number;
    
        @OneToOne(() => Donor)
        @JoinColumn({name:'id'})
        donor: Donor;
    
    }
    
    //DONOR.ts
    
    import { Column, Entity, PrimaryColumn } from "typeorm";
    
    
    @Entity('donor')
    export class Donor
    {
        
        @PrimaryColumn()
        id:number;
    
        @Column()
        name:string;
    
        @Column()
        dob:Date;
        
        @Column()
        date_of_reg:Date;
        
        @Column()
        blood_group:string;
    
        @Column()
        address:string;
    
        @Column()
        city:string;
    
        @Column()
        pincode:string;
    
    }
    
    //BloodDonationController.ts
    
    
    import { BaseEntity, getRepository } from "typeorm";
    import { Request, Response } from 'express';
    import { BloodDonation } from "../entities/blood_donation";
    
    class BloodDonationController extends BaseEntity{
    
        
        static Data = async (req:Request, res:Response)=>
        {
           
            const Header = req.headers;
          
            if(!(Header))
            {
                res.status(400).send();
            }
    
            const userRepo = getRepository(BloodDonation);
    
            let object:any = BloodDonation;
    
            try
            {
                 
                object = await userRepo.createQueryBuilder('blood_donation')
                .leftJoin('blood_donation.donor','donor')
                .select(['blood_donation.quantity','donor.name'])
                .getMany();
    
                    res.status(200).json(
                { 
                    response:{
                        object
                    }, 
                    success: true
                });
                    return;
             
            }
            catch(error)
            {
                res.status(401).send(error);
            }
        }
    
    }
    
    export default BloodDonationController;
    
    
    
    **My Response**
    
    
    {
        "response": {
            "object": [
                {
                    "quantity": 1.2,
                    "donor": {
                        "name": "Abhishek"
                    }
                },
                {
                    "quantity": 1.5,
                    "donor": {
                        "name": "Vishwas"
                    }
                },
                {
                    "quantity": 1.5,
                    "donor": {
                        "name": "Gaurav"
                    }
                },
                {
                    "quantity": 1.8,
                    "donor": null
                }
            ]
        },
        "success": true
    }
    

    【讨论】:

      【解决方案3】:

      晚上好)当你使用左连接时,你不能只连接特定的列,因为左连接总是连接左表的所有字段。但你可以选择它们。

      【讨论】:

        【解决方案4】:

        您有一些语法错误。你的一些别名也没有意义,但我确定你有这个意图。

        SELECT 
        DISTINCT 
          distinctAlias.profile_id as ids_profile_id
        FROM (
           SELECT
           profile.id AS profile_id
           --...,
           FROM user_profiles profile
            LEFT JOIN media_images avatarPhoto ON avatarPhoto.id=profile.avatar_photo_id
            LEFT JOIN media_images coverPhoto ON coverPhoto.id=profile.cover_photo_id
            LEFT JOIN data_countries country ON country.id=profile.primary_country_id
            LEFT JOIN data_cities city ON city.id=profile.primary_city_id 
            LEFT JOIN media_images image ON image.user_id=profile.id
            LEFT JOIN user_practiced_sports practicedSport ON practicedSport.user_id=profile.id
            LEFT JOIN "user" "event" ON event.id = profile.id
            LEFT JOIN user_auth auth ON auth.profile_id=profile.id
        
            -- join on sport event id here - if you have one
            -- LEFT JOIN sport_events ON ....
        
           WHERE auth.registered = true
           AND auth.blocked = false
        ) distinctAlias
        
        ORDER BY profile_id -- ASC is the default
        LIMIT 15
        

        【讨论】:

          【解决方案5】:

          你可以使用 .leftJoin(property, alias).addSelect([alias.fieldToSelect]) 代替 leftJoinAndSelect()

          示例: 假设您已经在实体中编写了关系,假设您有 table1.field1 加入到 table2.field2。你可以这样做,

            const data = await this.table1Repository.createQueryBuilder("t1")
                         .leftJoin('t1.relationName', 'alias')
                         .addSelect(['alias.fieldYouWantToSelect']);
          
          

          【讨论】:

            猜你喜欢
            • 2022-11-09
            • 1970-01-01
            • 2011-06-16
            • 2011-06-28
            • 1970-01-01
            • 1970-01-01
            • 2020-10-08
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多