feat(analyticsApi): added better api for page counts
Build and Push Docker image / build-and-push (push) Successful in 2m10s
Details
Build and Push Docker image / build-and-push (push) Successful in 2m10s
Details
This commit is contained in:
parent
23b0e7cf84
commit
fe232533c3
|
@ -14,44 +14,45 @@ import (
|
||||||
|
|
||||||
// initPageViewCount
|
// 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:
|
// It adds the following endpoint to the app:
|
||||||
// GET /api/analytics/pageViewCount
|
// GET /api/analytics/pageViewCount
|
||||||
//
|
//
|
||||||
// The endpoint expects the following query parameters:
|
// Query parameters:
|
||||||
//
|
//
|
||||||
// ?startDate=ISO 8601 formatted date (optional)
|
// ?startDate=ISO 8601 formatted date (optional)
|
||||||
// ?page=<page number>
|
// ?page=<page number>
|
||||||
// ?perPage=<results per page>
|
// ?perPage=<results per page>
|
||||||
// ?sort=<ASC|DESC> (default is ASC)
|
// ?sort=<ASC|DESC> (default is ASC)
|
||||||
//
|
//
|
||||||
// - `startDate`: An optional start date in ISO 8601 format (e.g., "2024-11-12T15:04:05Z").
|
// - `startDate`: 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.
|
// - `page`: Page number for pagination (default is 1).
|
||||||
// If not provided, the global count includes all views.
|
// - `perPage`: Number of results per page (default is 10).
|
||||||
// - `page`: Page number for pagination (default is 1).
|
// - `sort`: Sorting order, either `ASC` or `DESC` (default is ASC).
|
||||||
// - `perPage`: Number of results per page for pagination (default is 10).
|
|
||||||
// - `sort`: Sorting order, either `ASC` or `DESC` for ascending or descending order.
|
|
||||||
//
|
//
|
||||||
// Response format:
|
// Response format:
|
||||||
// [
|
|
||||||
//
|
//
|
||||||
// {
|
// {
|
||||||
// "id": <unique row id>,
|
// "page": <current page number>,
|
||||||
// "data": "<path>",
|
// "perPage": <results per page>,
|
||||||
// "count": <total view count since startDate>,
|
// "totalItems": <total number of items matching the filter>,
|
||||||
// "last_30_days_data": [
|
// "totalPages": <total number of pages>,
|
||||||
|
// "items": [
|
||||||
// {
|
// {
|
||||||
// "date": "YYYY-MM-DDTHH:MM:SSZ",
|
// "id": <unique row id>,
|
||||||
// "count": <daily count>
|
// "path": "<path>",
|
||||||
|
// "count": <total view count since startDate>,
|
||||||
|
// "last_30_days_data": [
|
||||||
|
// {
|
||||||
|
// "date": "YYYY-MM-DDTHH:MM:SSZ",
|
||||||
|
// "count": <daily count>
|
||||||
|
// },
|
||||||
|
// ...
|
||||||
|
// ]
|
||||||
// },
|
// },
|
||||||
// ...
|
// ...
|
||||||
// ]
|
// ]
|
||||||
// },
|
// }
|
||||||
// ...
|
|
||||||
//
|
|
||||||
// ]
|
|
||||||
//
|
|
||||||
// `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) {
|
func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) {
|
||||||
|
|
||||||
e.Router.GET("/api/analytics/pageViewCount", func(c echo.Context) error {
|
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"))
|
page, _ := strconv.Atoi(c.QueryParam("page"))
|
||||||
if page < 1 {
|
if page < 1 {
|
||||||
page = 1
|
page = 1
|
||||||
|
@ -90,21 +91,45 @@ func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) {
|
||||||
|
|
||||||
offset := (page - 1) * perPage
|
offset := (page - 1) * perPage
|
||||||
|
|
||||||
type PageViewData struct {
|
// Fetch total items for pagination
|
||||||
ID int `json:"id"`
|
var totalItems int
|
||||||
Data string `json:"data"`
|
err = app.Dao().DB().
|
||||||
Count int `json:"count"`
|
NewQuery(`
|
||||||
Last30DaysData interface{} `json:"last_30_days_data"`
|
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().
|
err = app.Dao().DB().
|
||||||
NewQuery(`
|
NewQuery(`
|
||||||
SELECT
|
SELECT
|
||||||
(ROW_NUMBER() OVER()) AS id,
|
(ROW_NUMBER() OVER()) AS id,
|
||||||
view.path AS data,
|
view.path AS path,
|
||||||
(
|
(
|
||||||
SELECT COUNT(id)
|
SELECT COUNT(id)
|
||||||
FROM analyticsPageViews
|
FROM analyticsPageViews
|
||||||
|
@ -133,7 +158,7 @@ func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) {
|
||||||
GROUP BY
|
GROUP BY
|
||||||
view.path
|
view.path
|
||||||
ORDER BY
|
ORDER BY
|
||||||
data ` + sort + `
|
path ` + sort + `
|
||||||
LIMIT {:perPage} OFFSET {:offset}
|
LIMIT {:perPage} OFFSET {:offset}
|
||||||
`).
|
`).
|
||||||
Bind(dbx.Params{
|
Bind(dbx.Params{
|
||||||
|
@ -141,14 +166,23 @@ func initPageViewCount(app *pocketbase.PocketBase, e *core.ServeEvent) {
|
||||||
"perPage": perPage,
|
"perPage": perPage,
|
||||||
"offset": offset,
|
"offset": offset,
|
||||||
}).
|
}).
|
||||||
All(&result)
|
All(&items)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apis.NewApiError(500, "Failed to query page view data", err)
|
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 the final JSON response
|
||||||
return c.JSON(200, result)
|
return c.JSON(200, response)
|
||||||
}, apis.ActivityLogger(app))
|
}, apis.ActivityLogger(app))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue