From 0de32cd2cede8fba8b0e61d27a4b3d3ec80b96ea Mon Sep 17 00:00:00 2001 From: lekss361 Date: Mon, 11 May 2026 17:52:37 +0300 Subject: [PATCH] =?UTF-8?q?fix(analytics):=20dedupe=20comparables=20?= =?UTF-8?q?=E2=80=94=20domrf=5Fkn=5Fobjects=20has=203x=20snapshots=20per?= =?UTF-8?q?=20obj=5Fid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The comparables block on /analytics/recommend was showing the same ЖК multiple times (ЖК СТАРТ × 3, ЭХО ЛЕСА × 2 etc) because domrf_kn_objects has ~3 historical snapshots per obj_id. The previous query joined all rows and LIMIT 5 cherry-picked duplicates by flat_count. Fix: wrap base in CTE `latest_obj` with `DISTINCT ON (obj_id) ORDER BY obj_id, snapshot_date DESC` to pick only the latest snapshot per object before sorting by flat_count. --- backend/app/services/analytics_queries.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/backend/app/services/analytics_queries.py b/backend/app/services/analytics_queries.py index ff2361b9..89dcaf1b 100644 --- a/backend/app/services/analytics_queries.py +++ b/backend/app/services/analytics_queries.py @@ -2089,22 +2089,29 @@ def recommend_mix( FROM v_complex_full ORDER BY lower(canonical_name), cad_buildings_n DESC NULLS LAST ) + latest_obj AS ( + -- domrf_kn_objects содержит ~3 snapshot'а на obj_id; + -- берём только самый свежий, иначе comparables дублируются + SELECT DISTINCT ON (obj_id) * + FROM domrf_kn_objects + WHERE region_cd = :rc + AND district_name = :dn + AND (CAST(:cls AS TEXT) IS NULL OR obj_class = :cls) + ORDER BY obj_id, snapshot_date DESC NULLS LAST + ) SELECT o.obj_id, o.comm_name, o.dev_name, o.obj_class, o.flat_count, a.perc AS sold_perc, c.cad_quarter, c.latitude AS lat, c.longitude AS lon, c.cad_buildings_n AS buildings_n - FROM domrf_kn_objects o + FROM latest_obj o LEFT JOIN latest_agg la ON la.obj_id = o.obj_id LEFT JOIN domrf_kn_sales_agg a ON a.obj_id = la.obj_id AND a.snapshot_date = la.snap AND a.type = 'apartments' LEFT JOIN vcf_dedup c ON c.name_key = lower(o.comm_name) - WHERE o.region_cd = :rc - AND o.district_name = :dn - AND (CAST(:cls AS TEXT) IS NULL OR o.obj_class = :cls) ORDER BY o.flat_count DESC NULLS LAST LIMIT 5 """