0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-28 00:59:18 -05:00

fix(server): searching with both personIds and withPeople (#13254)

* use cte

* linting
This commit is contained in:
Mert 2024-10-07 15:44:04 -04:00 committed by GitHub
parent 5b00bc499f
commit 063969ca05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 11 additions and 29 deletions

View file

@ -26,7 +26,7 @@ import { asVector, searchAssetBuilder } from 'src/utils/database';
import { Instrumentation } from 'src/utils/instrumentation'; import { Instrumentation } from 'src/utils/instrumentation';
import { Paginated, PaginationResult, paginatedBuilder } from 'src/utils/pagination'; import { Paginated, PaginationResult, paginatedBuilder } from 'src/utils/pagination';
import { isValidInteger } from 'src/validation'; import { isValidInteger } from 'src/validation';
import { Repository, SelectQueryBuilder } from 'typeorm'; import { Repository } from 'typeorm';
@Instrumentation() @Instrumentation()
@Injectable() @Injectable()
@ -113,14 +113,6 @@ export class SearchRepository implements ISearchRepository {
return assets1; return assets1;
} }
private createPersonFilter(builder: SelectQueryBuilder<AssetFaceEntity>, personIds: string[]) {
return builder
.select(`${builder.alias}."assetId"`)
.where(`${builder.alias}."personId" IN (:...personIds)`, { personIds })
.groupBy(`${builder.alias}."assetId"`)
.having(`COUNT(DISTINCT ${builder.alias}."personId") = :personCount`, { personCount: personIds.length });
}
@GenerateSql({ @GenerateSql({
params: [ params: [
{ page: 1, size: 100 }, { page: 1, size: 100 },
@ -136,21 +128,12 @@ export class SearchRepository implements ISearchRepository {
}) })
async searchSmart( async searchSmart(
pagination: SearchPaginationOptions, pagination: SearchPaginationOptions,
{ embedding, userIds, personIds, ...options }: SmartSearchOptions, { embedding, userIds, ...options }: SmartSearchOptions,
): Paginated<AssetEntity> { ): Paginated<AssetEntity> {
let results: PaginationResult<AssetEntity> = { items: [], hasNextPage: false }; let results: PaginationResult<AssetEntity> = { items: [], hasNextPage: false };
await this.assetRepository.manager.transaction(async (manager) => { await this.assetRepository.manager.transaction(async (manager) => {
let builder = manager.createQueryBuilder(AssetEntity, 'asset'); let builder = manager.createQueryBuilder(AssetEntity, 'asset');
if (personIds?.length) {
const assetFaceBuilder = manager.createQueryBuilder(AssetFaceEntity, 'asset_face');
const cte = this.createPersonFilter(assetFaceBuilder, personIds);
builder
.addCommonTableExpression(cte, 'asset_face_ids')
.innerJoin('asset_face_ids', 'a', 'a."assetId" = asset.id');
}
builder = searchAssetBuilder(builder, options); builder = searchAssetBuilder(builder, options);
builder builder
.innerJoin('asset.smartSearch', 'search') .innerJoin('asset.smartSearch', 'search')

View file

@ -1,4 +1,5 @@
import _ from 'lodash'; import _ from 'lodash';
import { AssetFaceEntity } from 'src/entities/asset-face.entity';
import { AssetEntity } from 'src/entities/asset.entity'; import { AssetEntity } from 'src/entities/asset.entity';
import { AssetSearchBuilderOptions } from 'src/interfaces/search.interface'; import { AssetSearchBuilderOptions } from 'src/interfaces/search.interface';
import { Between, IsNull, LessThanOrEqual, MoreThanOrEqual, Not, SelectQueryBuilder } from 'typeorm'; import { Between, IsNull, LessThanOrEqual, MoreThanOrEqual, Not, SelectQueryBuilder } from 'typeorm';
@ -91,7 +92,6 @@ export function searchAssetBuilder(
withPeople, withPeople,
withSmartInfo, withSmartInfo,
personIds, personIds,
withExif,
withStacked, withStacked,
trashedAfter, trashedAfter,
trashedBefore, trashedBefore,
@ -128,15 +128,14 @@ export function searchAssetBuilder(
} }
if (personIds && personIds.length > 0) { if (personIds && personIds.length > 0) {
builder const cte = builder
.leftJoin(`${builder.alias}.faces`, 'faces') .createQueryBuilder()
.andWhere('faces.personId IN (:...personIds)', { personIds }) .select('faces."assetId"')
.addGroupBy(`${builder.alias}.id`) .from(AssetFaceEntity, 'faces')
.having('COUNT(DISTINCT faces.personId) = :personCount', { personCount: personIds.length }); .where('faces."personId" IN (:...personIds)', { personIds })
.groupBy(`faces."assetId"`)
if (withExif) { .having(`COUNT(DISTINCT faces."personId") = :personCount`, { personCount: personIds.length });
builder.addGroupBy('exifInfo.assetId'); builder.addCommonTableExpression(cte, 'face_ids').innerJoin('face_ids', 'a', 'a."assetId" = asset.id');
}
} }
if (withStacked) { if (withStacked) {