+ analytics
This commit is contained in:
@@ -20,6 +20,7 @@ import java.time.LocalDateTime
|
||||
import java.time.LocalTime
|
||||
import java.time.ZoneId
|
||||
import java.time.ZoneOffset
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
|
||||
@Service
|
||||
@@ -376,7 +377,7 @@ class CategoryService(
|
||||
"date",
|
||||
Document(
|
||||
"\$gte", Date.from(
|
||||
LocalDateTime.of(dateTo, LocalTime.MIN)
|
||||
LocalDateTime.of(dateFrom, LocalTime.MIN)
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.withZoneSameInstant(ZoneOffset.UTC).toInstant()
|
||||
)
|
||||
@@ -545,5 +546,195 @@ class CategoryService(
|
||||
.collectList()
|
||||
}
|
||||
|
||||
fun getCategorySummaries(dateFrom: LocalDate): Mono<List<Document>> {
|
||||
val sixMonthsAgo = Date.from(
|
||||
LocalDateTime.of(dateFrom, LocalTime.MIN)
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.withZoneSameInstant(ZoneOffset.UTC).toInstant()
|
||||
) // Пример даты, можно заменить на вычисляемую
|
||||
|
||||
val aggregation = listOf(
|
||||
// 1. Фильтр за последние 6 месяцев
|
||||
Document(
|
||||
"\$match",
|
||||
Document("date", Document("\$gte", sixMonthsAgo).append("\$lt", Date())).append("type.code", "INSTANT")
|
||||
),
|
||||
|
||||
// 2. Группируем по категории + (год, месяц)
|
||||
Document(
|
||||
"\$group", Document(
|
||||
"_id", Document("category", "\$category.\$id")
|
||||
.append("year", Document("\$year", "\$date"))
|
||||
.append("month", Document("\$month", "\$date"))
|
||||
)
|
||||
.append("totalAmount", Document("\$sum", "\$amount"))
|
||||
),
|
||||
|
||||
// 3. Подтягиваем информацию о категории
|
||||
Document(
|
||||
"\$lookup", Document("from", "categories")
|
||||
.append("localField", "_id.category")
|
||||
.append("foreignField", "_id")
|
||||
.append("as", "categoryInfo")
|
||||
),
|
||||
|
||||
// 4. Распаковываем массив категорий
|
||||
Document("\$unwind", "\$categoryInfo"),
|
||||
|
||||
// 5. Фильтруем по типу категории (EXPENSE)
|
||||
Document("\$match", Document("categoryInfo.type.code", "EXPENSE")),
|
||||
|
||||
// 6. Группируем обратно по категории, собирая все (год, месяц, total)
|
||||
Document(
|
||||
"\$group", Document("_id", "\$_id.category")
|
||||
.append("categoryName", Document("\$first", "\$categoryInfo.name"))
|
||||
.append("categoryType", Document("\$first", "\$categoryInfo.type.code"))
|
||||
.append("categoryIcon", Document("\$first", "\$categoryInfo.icon"))
|
||||
.append(
|
||||
"monthlySums", Document(
|
||||
"\$push", Document("year", "\$_id.year")
|
||||
.append("month", "\$_id.month")
|
||||
.append("total", "\$totalAmount")
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
// 7. Формируем единый массив из 6 элементов:
|
||||
// - каждый элемент = {year, month, total},
|
||||
// - если нет записей за месяц, ставим total=0
|
||||
Document(
|
||||
"\$project", Document("categoryName", 1)
|
||||
.append("categoryType", 1)
|
||||
.append("categoryIcon", 1)
|
||||
.append(
|
||||
"monthlySums", Document(
|
||||
"\$map", Document("input", Document("\$range", listOf(0, 6)))
|
||||
.append("as", "i")
|
||||
.append(
|
||||
"in", Document(
|
||||
"\$let", Document(
|
||||
"vars", Document(
|
||||
"subDate", Document(
|
||||
"\$dateSubtract", Document("startDate", Date())
|
||||
.append("unit", "month")
|
||||
.append("amount", "$\$i")
|
||||
)
|
||||
)
|
||||
)
|
||||
.append(
|
||||
"in", Document("year", Document("\$year", "$\$subDate"))
|
||||
.append("month", Document("\$month", "$\$subDate"))
|
||||
.append(
|
||||
"total", Document(
|
||||
"\$ifNull", listOf(
|
||||
Document(
|
||||
"\$getField", Document("field", "total")
|
||||
.append(
|
||||
"input", Document(
|
||||
"\$arrayElemAt", listOf(
|
||||
Document(
|
||||
"\$filter",
|
||||
Document(
|
||||
"input",
|
||||
"\$monthlySums"
|
||||
)
|
||||
.append("as", "ms")
|
||||
.append(
|
||||
"cond", Document(
|
||||
"\$and", listOf(
|
||||
Document(
|
||||
"\$eq",
|
||||
listOf(
|
||||
"$\$ms.year",
|
||||
Document(
|
||||
"\$year",
|
||||
"$\$subDate"
|
||||
)
|
||||
)
|
||||
),
|
||||
Document(
|
||||
"\$eq",
|
||||
listOf(
|
||||
"$\$ms.month",
|
||||
Document(
|
||||
"\$month",
|
||||
"$\$subDate"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
), 0.0
|
||||
)
|
||||
)
|
||||
)
|
||||
), 0.0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
// 8. Сортируем результат по имени категории
|
||||
Document("\$sort", Document("categoryName", 1))
|
||||
)
|
||||
|
||||
// Выполняем агрегацию
|
||||
return mongoTemplate.getCollection("transactions")
|
||||
.flatMapMany { it.aggregate(aggregation) }
|
||||
.map { document ->
|
||||
// Преобразуем _id в строку
|
||||
document["_id"] = document["_id"].toString()
|
||||
|
||||
// Получаем monthlySums и приводим к изменяемому списку
|
||||
val monthlySums = (document["monthlySums"] as? List<*>)?.map { monthlySum ->
|
||||
if (monthlySum is Document) {
|
||||
// Создаем копию Document, чтобы избежать изменений в исходном списке
|
||||
Document(monthlySum).apply {
|
||||
// Добавляем поле date
|
||||
val date = LocalDate.of(getInteger("year"), getInteger("month"), 1)
|
||||
this["date"] = date
|
||||
}
|
||||
} else {
|
||||
monthlySum
|
||||
}
|
||||
}?.toMutableList()
|
||||
|
||||
// Сортируем monthlySums по полю date
|
||||
val sortedMonthlySums = monthlySums?.sortedBy { (it as? Document)?.get("date") as? LocalDate }
|
||||
|
||||
// Рассчитываем разницу между текущим и предыдущим месяцем
|
||||
var previousMonthSum = 0.0
|
||||
sortedMonthlySums?.forEach { monthlySum ->
|
||||
if (monthlySum is Document) {
|
||||
val currentMonthSum = monthlySum.getDouble("total") ?: 0.0
|
||||
|
||||
// Рассчитываем разницу в процентах
|
||||
val difference = if (previousMonthSum != 0.0 && currentMonthSum != 0.0) {
|
||||
(((currentMonthSum - previousMonthSum) / previousMonthSum) * 100).toInt()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
// Добавляем поле difference
|
||||
monthlySum["difference"] = difference
|
||||
|
||||
// Обновляем previousMonthSum для следующей итерации
|
||||
previousMonthSum = currentMonthSum
|
||||
}
|
||||
}
|
||||
|
||||
// Обновляем документ с отсортированными и обновленными monthlySums
|
||||
document["monthlySums"] = sortedMonthlySums
|
||||
document
|
||||
}
|
||||
.collectList()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user