-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetupIndexes.js
More file actions
157 lines (152 loc) · 5.54 KB
/
Copy pathsetupIndexes.js
File metadata and controls
157 lines (152 loc) · 5.54 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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// MongoDB has no CREATE TABLE / FK / CHECK constraints — this script is the Mongo equivalent
// of the old sql/schema.sql: it creates every collection's indexes (uniqueness + query
// performance) up front. Idempotent — safe to re-run any time. Usage: npm run db:setup-indexes
//
// Note on what this does NOT replicate from the old Postgres schema:
// - No foreign keys, so referential integrity (e.g. a placement_application pointing at a
// real placement/student) is enforced in the service layer, not the database.
// - No CHECK constraints (cgpa range, positive durations, etc.) — enforced by Joi validation
// at the API boundary instead.
// - No native ENUM types — valid values (roles, statuses) are enforced by Joi, not storage.
const { connect, getDb, close } = require('../src/config/database');
const logger = require('../src/utils/logger');
const INDEX_PLAN = {
users: [
{ key: { email: 1 }, options: { unique: true } },
{ key: { google_id: 1 }, options: { unique: true, sparse: true } },
{ key: { role: 1 }, options: {} },
{ key: { institution_id: 1 }, options: {} },
// Sparse — set on only a small fraction of users at any time (an
// in-flight reset/verification link) — see user.repository.js's
// findByResetToken/findByEmailVerificationToken, both unindexed full
// collection scans before this.
{ key: { reset_password_token_hash: 1 }, options: { sparse: true } },
{ key: { email_verification_token_hash: 1 }, options: { sparse: true } },
],
institutions: [
{ key: { code: 1 }, options: { unique: true } },
{ key: { is_active: 1 }, options: {} },
],
departments: [
{ key: { institution_id: 1, code: 1 }, options: { unique: true } },
],
college_admins: [
{ key: { user_id: 1 }, options: { unique: true } },
{ key: { institution_id: 1 }, options: {} },
],
companies: [
{ key: { is_active: 1 }, options: {} },
],
hr: [
{ key: { user_id: 1 }, options: { unique: true } },
{ key: { company_id: 1 }, options: {} },
],
faculty: [
{ key: { user_id: 1 }, options: { unique: true } },
{ key: { institution_id: 1 }, options: {} },
{ key: { department_id: 1 }, options: {} },
],
students: [
{ key: { user_id: 1 }, options: { unique: true } },
{ key: { institution_id: 1, roll_number: 1 }, options: { unique: true } },
{ key: { department_id: 1 }, options: {} },
{ key: { batch_year: 1 }, options: {} },
],
placements: [
{ key: { institution_id: 1 }, options: {} },
{ key: { company_id: 1 }, options: {} },
{ key: { status: 1 }, options: {} },
],
placement_applications: [
{ key: { placement_id: 1, student_id: 1 }, options: { unique: true } },
{ key: { student_id: 1 }, options: {} },
{ key: { status: 1 }, options: {} },
{ key: { institution_id: 1 }, options: {} },
],
tests: [
{ key: { institution_id: 1 }, options: {} },
],
test_assignments: [
{ key: { test_id: 1, student_id: 1 }, options: { unique: true } },
{ key: { student_id: 1 }, options: {} },
{ key: { status: 1 }, options: {} },
{ key: { institution_id: 1 }, options: {} },
],
results: [
{ key: { test_assignment_id: 1 }, options: { unique: true } },
{ key: { student_id: 1 }, options: {} },
{ key: { test_id: 1 }, options: {} },
{ key: { institution_id: 1 }, options: {} },
],
notifications: [
{ key: { user_id: 1, is_read: 1 }, options: {} },
],
resume_builder: [
{ key: { student_id: 1 }, options: { unique: true } },
{ key: { institution_id: 1 }, options: {} },
],
activity_logs: [
{ key: { user_id: 1 }, options: {} },
{ key: { created_at: 1 }, options: {} },
],
achievements: [
{ key: { student_id: 1 }, options: {} },
{ key: { student_id: 1, achievement_type: 1 }, options: {} },
],
assessment_attempts: [
{ key: { student_id: 1 }, options: {} },
],
interview_attempts: [
{ key: { student_id: 1 }, options: {} },
],
interview_responses: [
{ key: { student_id: 1 }, options: {} },
],
resume_versions: [
{ key: { student_id: 1, created_at: -1 }, options: {} },
],
profile_data: [
{ key: { user_id: 1 }, options: { unique: true } },
],
user_data_states: [
{ key: { user_id: 1 }, options: { unique: true } },
],
batches: [
{ key: { institution_id: 1 }, options: {} },
{ key: { status: 1 }, options: {} },
],
batch_students: [
{ key: { batch_id: 1, student_id: 1 }, options: { unique: true } },
],
placement_records: [
{ key: { student_id: 1 }, options: {} },
],
messages: [
{ key: { sender_id: 1, receiver_id: 1, created_at: -1 }, options: {} },
{ key: { receiver_id: 1, sender_id: 1, created_at: -1 }, options: {} },
],
// Institution-agnostic practice-bank content — see models/question.model.js.
// question.repository.js#sampleRandom always $matches on category before
// $sample-ing; without this, every assigned-test draw was a full
// collection scan of the entire question bank before the random sample.
questions: [
{ key: { category: 1 }, options: {} },
],
};
async function main() {
await connect();
const db = getDb();
for (const [collectionName, indexes] of Object.entries(INDEX_PLAN)) {
for (const { key, options } of indexes) {
await db.collection(collectionName).createIndex(key, options);
}
logger.info(`Indexes ready: ${collectionName}`, { count: indexes.length });
}
logger.info('All indexes created/verified');
await close();
process.exit(0);
}
main().catch((err) => {
logger.error('Index setup failed', { error: err.message });
process.exit(1);
});