forked from Agora-Events/agora
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrecommended_events.sql
More file actions
82 lines (72 loc) · 2.39 KB
/
Copy pathrecommended_events.sql
File metadata and controls
82 lines (72 loc) · 2.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
-- ============================================================
-- Agora: Recommended Events Query
-- Strategy: Content-based filtering via category_id overlap
-- from the user's 3 most recent ticket purchases.
-- ============================================================
-- Step 1: Derive the categories from the user's last 3 purchases
WITH recent_purchases AS (
SELECT DISTINCT e.category_id
FROM tickets t
JOIN events e ON e.id = t.event_id
WHERE t.user_id = $1 -- :user_id
AND t.status = 'confirmed'
ORDER BY t.created_at DESC
LIMIT 3
),
-- Step 2: Score candidate events by how many purchased categories they match
scored_events AS (
SELECT
e.id,
e.title,
e.slug,
e.description,
e.start_time,
e.end_time,
e.location,
e.banner_url,
e.category_id,
c.name AS category_name,
e.organizer_id,
u.display_name AS organizer_name,
u.avatar_url AS organizer_avatar,
-- Minimum ticket price for this event (NULL → free)
(
SELECT MIN(tp.price)
FROM ticket_types tp
WHERE tp.event_id = e.id
AND tp.is_active = TRUE
) AS min_price,
-- Tickets remaining across all active ticket types
(
SELECT COALESCE(SUM(tp.quantity - tp.sold), 0)
FROM ticket_types tp
WHERE tp.event_id = e.id
AND tp.is_active = TRUE
) AS tickets_remaining,
-- Relevance: count of matching purchased categories (≥1 guaranteed by JOIN)
COUNT(rp.category_id) AS relevance_score
FROM events e
JOIN categories c ON c.id = e.category_id
JOIN users u ON u.id = e.organizer_id
JOIN recent_purchases rp ON rp.category_id = e.category_id
WHERE e.status = 'published'
AND e.start_time > NOW() -- future events only
-- Exclude events the user already has a ticket for
AND e.id NOT IN (
SELECT t2.event_id
FROM tickets t2
WHERE t2.user_id = $1
AND t2.status = 'confirmed'
)
GROUP BY
e.id, e.title, e.slug, e.description,
e.start_time, e.end_time, e.location,
e.banner_url, e.category_id, c.name,
e.organizer_id, u.display_name, u.avatar_url
)
SELECT *
FROM scored_events
ORDER BY
relevance_score DESC, -- most category overlap first
start_time ASC -- then soonest upcoming
LIMIT 12;