mapx icon indicating copy to clipboard operation
mapx copied to clipboard

Addition of a tool in MapX to have general statistics on a project

Open thomaspiller opened this issue 5 years ago • 4 comments

Creation of an interface in MapX so that administrators (and publishers ?) can have statistics on their project with an export tool to generate a PDF report.

Here is a list of suggestions of what could be displayed:

  • Project overview:
    • number of views
    • number of sources
    • number of sources without views (with an option to display the complete list)
  • Project popularity:
    • number of unique users (last month, in total)
    • map showing the location of users (approximation)
    • top 5 views
    • time spent by users consulting views (last month, in total)
  • Project quality:
    • project score
    • completeness of metadata (with an option to display detailed information)
    • ~publishers evaluation / ranking (?)~

thomaspiller avatar Dec 10 '20 07:12 thomaspiller

Very well summarized. I would however not provide the possibility to evaluate or rank the publishers

PierreLacroix avatar Dec 10 '20 07:12 PierreLacroix

Unfortunately, GitHub does not support SQL files. The 1st draft of the query is available in the following .txt file: sql_query.txt

thomaspiller avatar Jan 13 '22 14:01 thomaspiller

Thanks !

There are some tricks for SQL (or any code) : <details> tag + markdown code. A "copy to clipboard" button is then shown. Text files are fine, too.

sql_query.sql
WITH views_project_ids AS (
  SELECT
    id AS id_view
  FROM
    mx_views_latest
  WHERE
    project = 'MX-IY9-QCF-ILZ-UVO-07Y'
		OR data #> '{"projects"}' @> to_jsonb('MX-IY9-QCF-ILZ-UVO-07Y'::text)

	UNION

	SELECT
    jsonb_array_elements_text(views_external) AS id_view
  FROM
    mx_projects
  WHERE
    id = 'MX-IY9-QCF-ILZ-UVO-07Y'
),
views_project AS (
  SELECT
    id,
		data #> '{"title"}' AS view_title,
		data #>> '{"source", "layerInfo", "name"}' AS vt_source,
		type,
		readers @> '["public"]' AS public,
		project != 'MX-IY9-QCF-ILZ-UVO-07Y' AS external
  FROM
    mx_views_latest
  WHERE
    id IN (
      SELECT
        *
      FROM
        views_project_ids)),
views_count AS (
  SELECT
    COUNT(*)
  FROM
    views_project
),
public_views_count AS (
  SELECT
    COUNT(*)
  FROM
    views_project
  WHERE
    public
),
views_published_count AS (
  SELECT
    COUNT(*)
  FROM
    views_project
  WHERE
    NOT external
),
public_views_published_count AS (
  SELECT
    COUNT(*)
  FROM
    views_project
  WHERE
    NOT external
    AND public
),
sources AS (
  SELECT
    COUNT(*)
  FROM
    mx_sources
  WHERE
    project = 'MX-IY9-QCF-ILZ-UVO-07Y'
),
sources_with_view AS (
  SELECT
    COUNT(DISTINCT vt_source)
  FROM
    views_project
  WHERE
	  NOT external
),
admins_list AS (
  SELECT
    jsonb_array_elements_text(admins) AS admins
  FROM
    mx_projects
  WHERE
    id = 'MX-IY9-QCF-ILZ-UVO-07Y'
),
publishers_list AS (
  SELECT
    jsonb_array_elements_text(publishers) AS publishers
  FROM
    mx_projects
  WHERE
    id = 'MX-IY9-QCF-ILZ-UVO-07Y'
),
members_list AS (
  SELECT
    jsonb_array_elements_text(members) AS members
  FROM
    mx_projects
  WHERE
    id = 'MX-IY9-QCF-ILZ-UVO-07Y'
),
admins AS (
  SELECT
    COUNT(*)
  FROM
    admins_list
),
publishers AS (
  SELECT
    COUNT(*)
  FROM
    publishers_list
  WHERE
    publishers NOT IN (
      SELECT
        admins
      FROM
        admins_list)
),
members AS (
  SELECT
    COUNT(*)
  FROM
    members_list
  WHERE
    members NOT IN (
      SELECT
        admins
      FROM
        admins_list)
    AND members NOT IN (
      SELECT
        publishers
      FROM
        publishers_list)),
logs AS (
  SELECT
    id_log,
    ip_user,
    id_user,
    is_guest,
		data
  FROM
    mx_logs
  WHERE
    id_project = 'MX-IY9-QCF-ILZ-UVO-07Y'
    AND date_modified > (CURRENT_DATE - 365)),
connections AS (
  SELECT
    ip_user,
    id_user,
    is_guest,
	  count(*)
  FROM
    logs
  WHERE
    id_log = 'session_start'
		OR id_log = 'project_change'
  GROUP BY
	  ip_user,
    id_user,
    is_guest
),
connections_ip_country AS (
  SELECT
    c.id_user,
    c.is_guest,
    coalesce(m.country_name, 'unknown') AS country_name,
    m.country_iso_code AS country,
	  c.count
  FROM
    connections c
  LEFT JOIN
    mx_ip m ON c.ip_user <<= m.network
),
conn_by_country AS (
  SELECT
    country,
    country_name,
    SUM(count)
  FROM
    connections_ip_country
  GROUP BY
    country,
    country_name
  ORDER BY
    sum DESC
),
conn_by_country_json AS (
  SELECT
    json_agg(row_to_json(cc)) tbl
  FROM
    conn_by_country cc
),
conn_by_users AS (
  SELECT
    SUM(count)
  FROM
    connections
  WHERE
    NOT is_guest
),
conn_by_guests AS (
  SELECT
    SUM(count)
  FROM
    connections
  WHERE
    is_guest
),
conn_by_distinct_users AS (
  SELECT
    COUNT(DISTINCT id_user)
  FROM
    connections
  WHERE
    NOT is_guest
),
views_duration AS (
	SELECT
	  data #>> '{"id_view"}' AS view_id,
	  SUM(CAST(data #> '{"view_duration_seconds"}' AS numeric)) AS duration
	FROM
		logs
	WHERE
		id_log = 'view_remove'
	GROUP BY
	  data #>> '{"id_view"}'),
views_duration_join AS (
	SELECT
    d.view_id,
		v.view_title,
		v.type,
		v.public,
		v.external,
		d.duration
	FROM
		views_duration d,
		views_project v
	WHERE
	  d.view_id = v.id
	ORDER BY
	  duration DESC),
views_duration_json AS (
  SELECT
    json_agg(row_to_json(v)) tbl
  FROM
    views_duration_join v
	),
views_duration_total	AS (
	SELECT
			SUM(duration)
	FROM
		views_duration),
views_activation AS (
	SELECT
	  data #>> '{"id_view"}' AS view_id,
	  COUNT(*) AS activation
	FROM
		logs
	WHERE
		id_log = 'view_add'
	GROUP BY
	  data #>> '{"id_view"}'),
views_activation_join AS (
	SELECT
    a.view_id,
		v.view_title,
		v.type,
		v.public,
		v.external,
		a.activation
	FROM
		views_activation a,
		views_project v
	WHERE
	  a.view_id = v.id
	ORDER BY
	  activation DESC),
views_activation_json AS (
  SELECT
    json_agg(row_to_json(v)) tbl
  FROM
    views_activation_join v
	),
views_activation_total	AS (
	SELECT
			SUM(activation)
	FROM
		views_activation)
SELECT
  json_build_object('id','MX-IY9-QCF-ILZ-UVO-07Y',
										'nb_views', vc.count,
										'nb_public_views', pvc.count,
										'nb_views_published', vpc.count,
										'nb_public_views_published', pvpc.count,
										'nb_sources', s.count,
										'nb_sources_without_views', s.count - sv.count,
										'nb_admins', a.count,
										'nb_publishers', p.count,
										'nb_members', m.count,
										'conn', cu.sum + cg.sum,
										'conn_by_guests', cg.sum,
										'conn_by_users', cu.sum,
										'conn_by_distinct_users', cdu.count,
										'conn_by_country', cc.tbl,
										'views_duration', vdj.tbl,
										'views_duration_total', vdt.sum,
										'views_activation', vaj.tbl,
										'views_activation_total', vat.sum) AS project_stats
FROM
  views_count vc,
	public_views_count pvc,
	views_published_count vpc,
	public_views_published_count pvpc,
  sources s,
  sources_with_view sv,
  admins a,
  publishers p,
  members m,
	conn_by_guests cg,
  conn_by_users cu,
  conn_by_distinct_users cdu,
  conn_by_country_json cc,
	views_duration_json vdj,
	views_duration_total vdt,
	views_activation_json vaj,
	views_activation_total vat

fxi avatar Jan 13 '22 14:01 fxi

It would also be relevant to add a routine to warn admins about views that are not longer maintained in their project.

  • SQL query to list all views that were not updated from 6 months (or a year)
  • automatically set these views to private (readers >= members)
  • send an email to the admins each week with the results of the routine

thomaspiller avatar Jan 09 '23 14:01 thomaspiller