Kartoza - Using NOTIFY to Automatically Refresh Layers in QGIS
One of the most brilliant but little-known features of QGIS is the ability to trigger layer refreshes and events in response to notifications from PostgreSQL.
One of the most brilliant but little-known features of QGIS is the ability to trigger layer refreshes and events in response to notifications from PostgreSQL. This was developed by the wizards from Oslandia and is easily added to any existing table in your PostgreSQL database - including PostGIS tables. This feature was added in version 3.0 (see https://qgis.org/en/site/forusers/visualchangelog30/#feature-trigger-layer-refresh-or-layer-actions-from-postgresql-notify-signal).
Take for example this simple table:
emp-shared=# \d lineTable "public.line"Column | Type | Modifiers------------+---------------------------+---------------------------------------------------id | integer | not null default nextval('line_id_seq'::regclass)name | character varying(255) | not nullvoltage_kv | real | not nullsource_id | integer | not nullgeom | geometry(LineString,4326) |Indexes:"line_pkey" PRIMARY KEY, btree (id)"sidx_line_geom" gist (geom)
Let's first create a PostgreSQL function that will send the notification:
CREATE FUNCTION public.notify_qgis() RETURNS triggerLANGUAGE plpgsqlAS $$BEGIN NOTIFY qgis;RETURN NULL;END;$$;
To create notify on the table we simply add a couple of triggers to call the function on specific events. Here we are sending a signal on DELETE, INSERT and UPDATE events:
CREATE TRIGGER notify_qgis_editAFTER INSERT OR UPDATE OR DELETE OR TRANSACT ON public.lineFOR EACH STATEMENT EXECUTE PROCEDURE public.notify_qgis();
Now if we view our table definition it will look like this:
emp-shared=# \d lineTable "public.line"Column | Type | Modifiers------------+---------------------------+---------------------------------------------------id | integer | not null default nextval('line_id_seq'::regclass)name | character varying(255) | not nullvoltage_kv | real | not nullsource_id | integer | not nullgeom | geometry(LineString,4326) |Indexes:"line_pkey" PRIMARY KEY, btree (id)"sidx_line_geom" gist (geom)Triggers:notify_qgis_delete AFTER DELETE ON line FOR EACH STATEMENT EXECUTE PROCEDURE notify_qgis()notify_qgis_edit AFTER INSERT OR UPDATE ON line FOR EACH STATEMENT EXECUTE PROCEDURE notify_qgis()
The last thing you need to do is enable notifications in your layer rendering properties by ticking the 'refresh layer on notification' option:
Now you can test by leaving your QGIS Window open and adding features from another machine - you will see they get displayed automatically on yours!
For more info and a nice video demo, see Oslandia's post on NOTIFY including how to trigger actions from NOTIFY: https://oslandia.com/en/2017/10/07/refresh-your-maps-from-postgresql/
Tim Sutton
Tim started his career by working in Nature Conservation in South Africa. Some years later, around 1998, an opening in the newly formed GIS group in the organisation where he worked presented an opportunity to combine his love of the environment with his enthusiasm for computers. What followed quickly became a deep dive into GIS (including obtaining a Master's Degree in GIS and Environmental Studies) and Open Source. He discovered Linux, also around 1998, and became an ardent fan of using and creating Open Source software. The announcement of the first release of QGIS in 2002 was another key milestone, with Tim quickly becoming deeply involved in the development of QGIS, as well as helping to build the community platforms and governance structures around the project. Formerly the QGIS.org Board Chair, Tim was awarded perpetual Honorary QGIS PSC Member status in 2018 and continues to play an active role in many aspects of the QGIS project. Tim is also engaged in the broader Open Source GIS ecosystem, including having the honour of being an OSGEO Charter Member and promoting the wide array of world-changing Open Source GIS tools provided under the OSGEO umbrella (and beyond) to pretty much anyone who will listen.
Thanks for this wonderful post which helped me a lot! As a refinement, I would like to update only the layers in QGIS which have changed. The layer properties allow to update a layer only when receiving a certain notification message. If I had two layers in my QGIS project file (table a and table b) I would set them up that layer a only updates on receiving the message 'a' and layer b only on 'b'. The question is how I can tweak my trigger function? I was thinking I can just pass it a variable "layer" and use that in the NOTIFY statement. Changing the table a would call trigger function notifyqgis('a') and changing table b would call trigger function notifyqgis('b') but unfortunately, parameters are not so easy for trigger functions. Any idea how this could be achieved?