From 8a986d2e58e89e5b763123105a2387d3d4544ab5 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 13 Jan 2026 22:56:51 +0000 Subject: [PATCH] add indexes --- server/src/controllers/monitorController.ts | 2 +- server/src/db/models/Check.ts | 2 ++ .../checks/MongoChecksRepistory.ts | 6 +++++ .../monitors/IMonitorsRepository.ts | 1 + .../monitors/MongoMonitorsRepository.ts | 6 +++++ server/src/service/business/monitorService.ts | 22 ++++++++++--------- 6 files changed, 28 insertions(+), 11 deletions(-) diff --git a/server/src/controllers/monitorController.ts b/server/src/controllers/monitorController.ts index ba0a237bf..9c117e9af 100644 --- a/server/src/controllers/monitorController.ts +++ b/server/src/controllers/monitorController.ts @@ -231,7 +231,7 @@ class MonitorController { throw new AppError({ message: "Cannot get file from buffer", status: 400 }); } - const monitors = await this.monitorService.createBulkMonitors({ fileData, userId, teamId }); + const monitors = await this.monitorService.createBulkMonitors(fileData, userId, teamId); return res.status(200).json({ success: true, diff --git a/server/src/db/models/Check.ts b/server/src/db/models/Check.ts index fe6f16836..c176aa3bb 100644 --- a/server/src/db/models/Check.ts +++ b/server/src/db/models/Check.ts @@ -288,7 +288,9 @@ const CheckSchema = new Schema( CheckSchema.index({ updatedAt: 1 }); CheckSchema.index({ "metadata.monitorId": 1, updatedAt: 1 }); CheckSchema.index({ "metadata.monitorId": 1, updatedAt: -1 }); +CheckSchema.index({ "metadata.monitorId": 1, createdAt: -1 }); CheckSchema.index({ "metadata.teamId": 1, updatedAt: -1 }); +CheckSchema.index({ "metadata.teamId": 1, createdAt: -1 }); const CheckModel = model("Check", CheckSchema); diff --git a/server/src/repositories/checks/MongoChecksRepistory.ts b/server/src/repositories/checks/MongoChecksRepistory.ts index f5c398fc8..10b482fb2 100644 --- a/server/src/repositories/checks/MongoChecksRepistory.ts +++ b/server/src/repositories/checks/MongoChecksRepistory.ts @@ -178,10 +178,15 @@ class MongoChecksRepistory implements IChecksRepository { } const mongoIds = monitorIds.map((id) => new mongoose.Types.ObjectId(id)); const limitPerMonitor = 25; + const maxIntervalMs = Number(10 * 60 * 1000); + const bufferMs = Number(maxIntervalMs); + const lookbackMs = 25 * maxIntervalMs + bufferMs; + const cutoffDate = new Date(Date.now() - lookbackMs); const checkGroups = await CheckModel.aggregate([ { $match: { "metadata.monitorId": { $in: mongoIds }, + createdAt: { $gte: cutoffDate }, }, }, { @@ -197,6 +202,7 @@ class MongoChecksRepistory implements IChecksRepository { }, }, ]); + return checkGroups.reduce((acc, group) => { const monitorId = group._id.toString(); acc[monitorId] = (group.latestChecks ?? []).map((doc: CheckDocument) => this.toEntity(doc)); diff --git a/server/src/repositories/monitors/IMonitorsRepository.ts b/server/src/repositories/monitors/IMonitorsRepository.ts index 99131cb4b..fc69d5740 100644 --- a/server/src/repositories/monitors/IMonitorsRepository.ts +++ b/server/src/repositories/monitors/IMonitorsRepository.ts @@ -13,6 +13,7 @@ export interface TeamQueryConfig { export interface IMonitorsRepository { // create create(monitor: Monitor, teamId: string, userId: string): Promise; + createBulkMonitors(monitors: Monitor[]): Promise; // single fetch findById(monitorId: string): Promise; diff --git a/server/src/repositories/monitors/MongoMonitorsRepository.ts b/server/src/repositories/monitors/MongoMonitorsRepository.ts index 49687c339..383442ac1 100644 --- a/server/src/repositories/monitors/MongoMonitorsRepository.ts +++ b/server/src/repositories/monitors/MongoMonitorsRepository.ts @@ -12,6 +12,12 @@ class MongoMonitorsRepository implements IMonitorsRepository { return this.toEntity(saved); }; + createBulkMonitors = async (monitors: Monitor[]): Promise => { + const newMonitors = monitors.map((monitor) => new MonitorModel({ ...monitor, notifications: undefined })); + await MonitorModel.bulkSave(newMonitors); + return monitors; + }; + findById = async (MonitorModelId: string): Promise => { const monitor = await MonitorModel.findById(MonitorModelId); if (!monitor) { diff --git a/server/src/service/business/monitorService.ts b/server/src/service/business/monitorService.ts index 45a2fc235..0f027b5b8 100644 --- a/server/src/service/business/monitorService.ts +++ b/server/src/service/business/monitorService.ts @@ -1,8 +1,10 @@ import { createMonitorsBodyValidation } from "@/validation/joi.js"; import { NormalizeData } from "@/utils/dataUtils.js"; import { type Monitor } from "@/types/index.js"; +import type { MonitorType } from "@/types/monitor.js"; import type { IMonitorsRepository } from "@/repositories/index.js"; import { AppError } from "../infrastructure/errorService.js"; + const SERVICE_NAME = "MonitorService"; export interface IMonitorService { @@ -11,7 +13,7 @@ export interface IMonitorService { // create createMonitor(teamId: string, userId: string, body: Monitor): Promise; - createBulkMonitors(args: { fileData: string; userId: string; teamId: string }): Promise; + createBulkMonitors(fileData: string, userId: string, teamId: string): Promise; addDemoMonitors(args: { userId: string; teamId: string }): Promise; // read @@ -31,7 +33,7 @@ export interface IMonitorService { getMonitorsByTeamId(args: { teamId: string; limit?: number; - type?: string | string[]; + type?: MonitorType | MonitorType[]; page?: number; rowsPerPage?: number; filter?: string; @@ -42,7 +44,7 @@ export interface IMonitorService { getMonitorsWithChecksByTeamId(args: { teamId: string; limit?: number; - type?: string | string[]; + type?: MonitorType | MonitorType[]; page?: number; rowsPerPage?: number; filter?: string; @@ -136,7 +138,7 @@ export class MonitorService implements IMonitorService { this.jobQueue.addJob(monitor.id, monitor); }; - createBulkMonitors = async ({ fileData, userId, teamId }: { fileData: string; userId: string; teamId: string }): Promise => { + createBulkMonitors = async (fileData: string, userId: string, teamId: string): Promise => { const { parse } = this.papaparse; return new Promise((resolve, reject) => { @@ -167,10 +169,10 @@ export class MonitorService implements IMonitorService { throw this.errorService.createServerError("CSV file contains no data rows"); } - const enrichedData = data.map((monitor: any) => ({ + const enrichedData = data.map((monitor: Monitor) => ({ + ...monitor, userId, teamId, - ...monitor, description: monitor.description || monitor.name || monitor.url, name: monitor.name || monitor.url, type: monitor.type || "http", @@ -178,11 +180,11 @@ export class MonitorService implements IMonitorService { await createMonitorsBodyValidation.validateAsync(enrichedData); - const monitors = await this.db.monitorModule.createBulkMonitors(enrichedData); + const monitors = await this.monitorsRepository.createBulkMonitors(enrichedData); await Promise.all( - monitors.map(async (monitor: any) => { - this.jobQueue.addJob(monitor._id, monitor); + monitors.map(async (monitor: Monitor) => { + this.jobQueue.addJob(monitor.id, monitor); }) ); @@ -334,7 +336,7 @@ export class MonitorService implements IMonitorService { }: { teamId: string; limit?: number; - type?: string | string[]; + type?: MonitorType | MonitorType[]; page?: number; rowsPerPage?: number; filter?: string;