Add aggregate queries for uptime monitor stats

This commit is contained in:
Alex Holliday committed 2024-12-30 14:57:19 -08:00
1 parent 0551eb010d
commit 5391145a9a
1 file changed
+179
+179
View File
@@ -304,6 +304,184 @@ const calculateGroupStats = (group) => {
};
};
/**
* Get uptime details by monitor ID
* @async
* @param {Express.Request} req
* @param {Express.Response} res
* @returns {Promise<Monitor>}
* @throws {Error}
*/
const getUptimeDetailsById = async (req) => {
try {
const { monitorId } = req.params;
const monitor = await Monitor.findById(monitorId);
if (monitor === null || monitor === undefined) {
throw new Error(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId));
}
const { dateRange, normalize } = req.query;
const dates = getDateRange(dateRange);
const currentTime = new Date();
// Build pipeline
const aggregateResults = await Check.aggregate([
{
$match: { monitorId: monitor._id },
},
{
$sort: { createdAt: 1 },
},
{
$group: {
_id: null,
latestCheck: { $last: "$$ROOT" },
lastFalseCheck: {
$last: {
$cond: [{ $eq: ["$status", false] }, "$$ROOT", null],
},
},
firstCheck: { $first: "$$ROOT" },
averageResponseTime: { $avg: "$responseTime" },
upChecks: {
$sum: {
$cond: [{ $eq: ["$status", true] }, 1, 0],
},
},
totalChecks: { $sum: 1 },
},
},
{
$project: {
timeSinceLastCheck: {
$subtract: [currentTime, "$latestCheck.createdAt"],
},
latestResponseTime: "$latestCheck.responseTime",
averageResponseTime: "$averageResponseTime",
latestStatus: "$latestCheck.status",
uptimeDuration: {
$cond: [
{ $eq: ["$latestCheck.status", false] },
0,
{
$subtract: [
currentTime,
{
$ifNull: ["$lastFalseCheck.createdAt", "$firstCheck.createdAt"],
},
],
},
],
},
uptimeDecimal: {
$divide: ["$upChecks", "$totalChecks"],
},
},
},
]);
const formatLookup = {
day: "%Y-%m-%d-%H",
week: "%Y-%m-%d-%H",
month: "%Y-%m-%d",
};
const dateString = formatLookup[dateRange];
const dateRangeResults = await Check.aggregate([
{
$match: {
monitorId: monitor._id,
createdAt: { $gte: dates.start, $lte: dates.end },
},
},
{
$group: {
_id: null,
totalChecks: { $sum: 1 },
upChecks: { $sum: { $cond: [{ $eq: ["$status", true] }, 1, 0] } },
avgResponseTime: { $avg: "$responseTime" },
},
},
{
$addFields: {
uptimePercentage: {
$multiply: [{ $divide: ["$upChecks", "$totalChecks"] }, 100],
},
},
},
{
$lookup: {
from: "checks",
let: { monitorId: monitor._id, start: dates.start, end: dates.end },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: ["$monitorId", "$$monitorId"] },
{ $gte: ["$createdAt", "$$start"] },
{ $lte: ["$createdAt", "$$end"] },
],
},
},
},
{
$sort: { createdAt: 1 },
},
{
$group: {
_id: {
$dateToString: {
format: dateString,
date: "$createdAt",
},
},
upChecks: {
$sum: {
$cond: [{ $eq: ["$status", true] }, 1, 0],
},
},
totalChecks: { $sum: 1 },
avgResponseTime: { $avg: "$responseTime" },
},
},
{
$project: {
avgResponseTime: 1,
groupUptimePercentage: { $divide: ["$upChecks", "$totalChecks"] },
},
},
],
as: "groupedResults",
},
},
{
$unwind: "$groupedResults",
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$groupedResults",
{ overallUptimePercentage: "$uptimePercentage" },
],
},
},
},
{
$sort: { _id: 1 },
},
]);
return { aggregateResults, dateRangeResults };
} catch (error) {
error.service = SERVICE_NAME;
error.method = "getUptimeDetailsById";
throw error;
}
};
/**
* Get stats by monitor ID
* @async
@@ -652,6 +830,7 @@ export {
getAllMonitorsWithUptimeStats,
getMonitorStatsById,
getMonitorById,
getUptimeDetailsById,
getMonitorsAndSummaryByTeamId,
getMonitorsByTeamId,
createMonitor,