feat(analyticsApi): added better api for page counts
Build and Push Docker image / build-and-push (push) Successful in 2m10s Details

This commit is contained in:
Valentin Kolb 2024-11-13 01:05:14 +01:00
parent 23b0e7cf84
commit fe232533c3
1 changed files with 71 additions and 37 deletions

View File

@ -14,30 +14,33 @@ import (
// initPageViewCount
//
// This endpoint is used to retrieve page view counts for each unique path.
// This endpoint is used to retrieve paginated page view counts for each unique path.
// It adds the following endpoint to the app:
// GET /api/analytics/pageViewCount
//
// The endpoint expects the following query parameters:
// Query parameters:
//
// ?startDate=ISO 8601 formatted date (optional)
// ?page=<page number>
// ?perPage=<results per page>
// ?sort=<ASC|DESC> (default is ASC)
//
// - `startDate`: An optional start date in ISO 8601 format (e.g., "2024-11-12T15:04:05Z").
// If provided, the global count reflects views from this date onward.
// If not provided, the global count includes all views.
// - `startDate`: Optional start date in ISO 8601 format (e.g., "2024-11-12T15:04:05Z").
// - `page`: Page number for pagination (default is 1).
// - `perPage`: Number of results per page for pagination (default is 10).
// - `sort`: Sorting order, either `ASC` or `DESC` for ascending or descending order.
// - `perPage`: Number of results per page (default is 10).
// - `sort`: Sorting order, either `ASC` or `DESC` (default is ASC).
//
// Response format:
// [
//
// {
// "page": <current page number>,
// "perPage": <results per page>,
// "totalItems": <total number of items matching the filter>,
// "totalPages": <total number of pages>,
// "items": [
// {
// "id": <unique row id>,
// "data": "<path>",
// "path": "<path>",
// "count": <total view count since startDate>,
// "last_30_days_data": [
// {
@ -48,10 +51,8 @@ import (
// ]
// },
// ...
//
// ]
//
// `last_30_days_data` always provides daily counts for the most recent 30 days regardless of the `startDate` parameter.
// }
func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) {
e.Router.GET("/api/analytics/pageViewCount", func(c echo.Context) error {
@ -72,7 +73,7 @@ func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) {
}
}
// Get pagination and sorting parameters
// Pagination and sorting parameters
page, _ := strconv.Atoi(c.QueryParam("page"))
if page < 1 {
page = 1
@ -90,21 +91,45 @@ func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) {
offset := (page - 1) * perPage
type PageViewData struct {
ID int `json:"id"`
Data string `json:"data"`
Count int `json:"count"`
Last30DaysData interface{} `json:"last_30_days_data"`
// Fetch total items for pagination
var totalItems int
err = app.Dao().DB().
NewQuery(`
SELECT COUNT(DISTINCT path) as total
FROM analyticsPageViews
WHERE created >= {:startDate}
`).
Bind(dbx.Params{
"startDate": startDate,
}).
Row(&totalItems)
if err != nil {
return apis.NewApiError(500, "Failed to count total items", err)
}
var result []PageViewData
totalPages := (totalItems + perPage - 1) / perPage // Calculate total pages
// Execute the query with nested JSON aggregation, pagination, and sorting
// Define the structure for items
type Last30DaysData struct {
Date string `json:"date"`
Count int `json:"count"`
}
type Item struct {
ID int `json:"id"`
Path string `json:"path"`
Count int `json:"count"`
Last30DaysData []Last30DaysData `json:"last_30_days_data"`
}
// Query paginated items
var items []Item
err = app.Dao().DB().
NewQuery(`
SELECT
(ROW_NUMBER() OVER()) AS id,
view.path AS data,
view.path AS path,
(
SELECT COUNT(id)
FROM analyticsPageViews
@ -133,7 +158,7 @@ func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) {
GROUP BY
view.path
ORDER BY
data ` + sort + `
path ` + sort + `
LIMIT {:perPage} OFFSET {:offset}
`).
Bind(dbx.Params{
@ -141,14 +166,23 @@ func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) {
"perPage": perPage,
"offset": offset,
}).
All(&result)
All(&items)
if err != nil {
return apis.NewApiError(500, "Failed to query page view data", err)
}
// Final response structure
response := map[string]interface{}{
"page": page,
"perPage": perPage,
"totalItems": totalItems,
"totalPages": totalPages,
"items": items,
}
// Return the final JSON response
return c.JSON(200, result)
return c.JSON(200, response)
}, apis.ActivityLogger(app))
}