mirror of
https://github.com/immich-app/immich
synced 2026-08-22 13:13:05 +00:00
fix(server): avoid GROUP BY on full person row in getAllForUser
Aggregate visible face counts per person in a narrow subquery grouped only by asset_face.personId, then join back to person. Fixes #30562
This commit is contained in:
parent
0293414abd
commit
717707fa0c
2 changed files with 36 additions and 26 deletions
|
|
@ -28,38 +28,44 @@ select
|
|||
"person".*
|
||||
from
|
||||
"person"
|
||||
inner join "asset_face" on "asset_face"."personId" = "person"."id"
|
||||
inner join "asset" on "asset_face"."assetId" = "asset"."id"
|
||||
and "asset"."visibility" = 'timeline'
|
||||
and "asset"."deletedAt" is null
|
||||
inner join (
|
||||
select
|
||||
"asset_face"."personId" as "personId",
|
||||
count("asset_face"."assetId") as "faceCount"
|
||||
from
|
||||
"asset_face"
|
||||
inner join "asset" on "asset_face"."assetId" = "asset"."id"
|
||||
and "asset"."visibility" = 'timeline'
|
||||
and "asset"."deletedAt" is null
|
||||
where
|
||||
"asset_face"."deletedAt" is null
|
||||
and "asset_face"."isVisible" is true
|
||||
group by
|
||||
"asset_face"."personId"
|
||||
) as "face_counts" on "face_counts"."personId" = "person"."id"
|
||||
where
|
||||
"person"."ownerId" = $1
|
||||
and "asset_face"."deletedAt" is null
|
||||
and "asset_face"."isVisible" is true
|
||||
and "person"."isHidden" = $2
|
||||
group by
|
||||
"person"."id"
|
||||
having
|
||||
(
|
||||
"person"."name" != $3
|
||||
or count("asset_face"."assetId") >= COALESCE(
|
||||
and (
|
||||
"person"."name" != $2
|
||||
or "face_counts"."faceCount" >= COALESCE(
|
||||
(
|
||||
SELECT
|
||||
value -> 'people' ->> 'minimumFaces'
|
||||
FROM
|
||||
user_metadata
|
||||
WHERE
|
||||
"userId" = $4
|
||||
"userId" = $3
|
||||
AND key = 'preferences'
|
||||
),
|
||||
'3'
|
||||
)::int
|
||||
)
|
||||
and "person"."isHidden" = $4
|
||||
order by
|
||||
"person"."isHidden" asc,
|
||||
"person"."isFavorite" desc,
|
||||
NULLIF(person.name, '') is null asc,
|
||||
count("asset_face"."assetId") desc,
|
||||
"face_counts"."faceCount" desc,
|
||||
NULLIF(person.name, '') asc nulls last,
|
||||
"person"."createdAt"
|
||||
limit
|
||||
|
|
|
|||
|
|
@ -149,26 +149,29 @@ export class PersonRepository {
|
|||
|
||||
@GenerateSql({ params: [{ take: 1, skip: 0 }, DummyValue.UUID] })
|
||||
async getAllForUser(pagination: PaginationOptions, userId: string, options?: PersonSearchOptions) {
|
||||
const items = await this.db
|
||||
.selectFrom('person')
|
||||
.selectAll('person')
|
||||
.innerJoin('asset_face', 'asset_face.personId', 'person.id')
|
||||
const faceCounts = this.db
|
||||
.selectFrom('asset_face')
|
||||
.innerJoin('asset', (join) =>
|
||||
join
|
||||
.onRef('asset_face.assetId', '=', 'asset.id')
|
||||
.on('asset.visibility', '=', sql.lit(AssetVisibility.Timeline))
|
||||
.on('asset.deletedAt', 'is', null),
|
||||
)
|
||||
.where('person.ownerId', '=', userId)
|
||||
.select(['asset_face.personId as personId', (eb) => eb.fn.count('asset_face.assetId').as('faceCount')])
|
||||
.where('asset_face.deletedAt', 'is', null)
|
||||
.where('asset_face.isVisible', 'is', true)
|
||||
.orderBy('person.isHidden', 'asc')
|
||||
.orderBy('person.isFavorite', 'desc')
|
||||
.having((eb) =>
|
||||
.groupBy('asset_face.personId');
|
||||
|
||||
const items = await this.db
|
||||
.selectFrom('person')
|
||||
.selectAll('person')
|
||||
.innerJoin(faceCounts.as('face_counts'), 'face_counts.personId', 'person.id')
|
||||
.where('person.ownerId', '=', userId)
|
||||
.where((eb) =>
|
||||
eb.or([
|
||||
eb('person.name', '!=', ''),
|
||||
eb(
|
||||
(innerEb) => innerEb.fn.count('asset_face.assetId'),
|
||||
'face_counts.faceCount',
|
||||
'>=',
|
||||
sql<number>`COALESCE(
|
||||
(SELECT value -> 'people' ->> 'minimumFaces'
|
||||
|
|
@ -180,7 +183,8 @@ export class PersonRepository {
|
|||
),
|
||||
]),
|
||||
)
|
||||
.groupBy('person.id')
|
||||
.orderBy('person.isHidden', 'asc')
|
||||
.orderBy('person.isFavorite', 'desc')
|
||||
.$if(!!options?.closestFaceAssetId, (qb) =>
|
||||
qb.orderBy((eb) =>
|
||||
eb(
|
||||
|
|
@ -201,7 +205,7 @@ export class PersonRepository {
|
|||
.$if(!options?.closestFaceAssetId, (qb) =>
|
||||
qb
|
||||
.orderBy(sql`NULLIF(person.name, '') is null`, 'asc')
|
||||
.orderBy((eb) => eb.fn.count('asset_face.assetId'), 'desc')
|
||||
.orderBy('face_counts.faceCount', 'desc')
|
||||
.orderBy(sql`NULLIF(person.name, '')`, (om) => om.asc().nullsLast())
|
||||
.orderBy('person.createdAt'),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue