From d90aaedc0060017c8d17825127a8448797a014ca Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Fri, 1 May 2026 19:16:53 +0300 Subject: [PATCH] skip duplicated records ids from the IN expand --- CHANGELOG.md | 2 ++ core/record_query_expand.go | 13 ++++++++-- core/record_query_expand_test.go | 42 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d52ba71..3c2e0958 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Reload trusted proxy info UI after settings save. +- Minor expand query optimization that skips the duplicated record ids from the `IN` list. + ## v0.37.4 diff --git a/core/record_query_expand.go b/core/record_query_expand.go index 2869c1da..c8472d2d 100644 --- a/core/record_query_expand.go +++ b/core/record_query_expand.go @@ -162,11 +162,20 @@ func (app *BaseApp) expandRecords(records []*Record, expandPath string, fetchFun // --------------------------------------------------------------- - // extract the id of the relations to expand + // extract the unique ids of the relations to expand + // (the initial size assumes that most of the relations are single and unique) + existsSet := make(map[string]struct{}, len(records)) relIds := make([]string, 0, len(records)) for _, record := range records { - relIds = append(relIds, record.GetStringSlice(relField.Name)...) + ids := record.GetStringSlice(relField.Name) + for _, id := range ids { + if _, ok := existsSet[id]; !ok { + existsSet[id] = struct{}{} + relIds = append(relIds, id) + } + } } + existsSet = nil // fetch rels rels, relsErr := fetchFunc(relCollection, relIds) diff --git a/core/record_query_expand_test.go b/core/record_query_expand_test.go index 04b5cbf1..3e23c509 100644 --- a/core/record_query_expand_test.go +++ b/core/record_query_expand_test.go @@ -1,11 +1,15 @@ package core_test import ( + "context" + "database/sql" "encoding/json" "errors" "strings" "testing" + "time" + "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/tests" "github.com/pocketbase/pocketbase/tools/list" @@ -484,3 +488,41 @@ func TestBackRelationExpandSingeVsArrayResult(t *testing.T) { } } } + +func TestExpandRecordsQuerySkipDuplicatedIds(t *testing.T) { + t.Parallel() + + app, _ := tests.NewTestApp() + defer app.Cleanup() + + // fetch records that are known to have at least 1 common relation between them + records, err := app.FindRecordsByIds("demo1", []string{"84nmscqy84lsi1t", "al1h9ijdeojtsjy"}) + if err != nil { + t.Fatal(err) + } + + // log selects + concurrentQueries := []string{} + app.ConcurrentDB().(*dbx.DB).QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) { + concurrentQueries = append(concurrentQueries, sql) + } + app.ConcurrentDB().(*dbx.DB).ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) { + concurrentQueries = append(concurrentQueries, sql) + } + + // expand + failed := app.ExpandRecords(records, []string{"rel_many"}, nil) + if len(failed) > 0 { + t.Fatalf("Expected no expand errors, got %v", failed) + } + + if len(concurrentQueries) != 1 { + t.Fatalf("Expected exactly 1 expand query, got %d:\n%v", len(concurrentQueries), concurrentQueries) + } + + // "oap640cot4yru2s" is used in both relations but must exists only once + expected := "SELECT `users`.* FROM `users` WHERE `users`.`id` IN ('oap640cot4yru2s', 'bgs820n361vj1qd', '4q1xlclmfloku33')" + if concurrentQueries[0] != expected { + t.Fatalf("Expected query\n%v\ngot\n%v", expected, concurrentQueries[0]) + } +}