{"id":10494,"date":"2024-03-27T15:24:14","date_gmt":"2024-03-27T14:24:14","guid":{"rendered":"https:\/\/blog.capdata.fr\/?p=10494"},"modified":"2024-03-27T15:24:14","modified_gmt":"2024-03-27T14:24:14","slug":"pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage","status":"publish","type":"post","link":"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/","title":{"rendered":"pg_dirtyread o\u00f9 comment r\u00e9parer facilement un delete sauvage"},"content":{"rendered":"<a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-twitter nolightbox\" data-provider=\"twitter\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Twitter\" href=\"https:\/\/twitter.com\/intent\/tweet?url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F10494&#038;text=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"twitter\" title=\"Share on Twitter\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/twitter.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-linkedin nolightbox\" data-provider=\"linkedin\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Linkedin\" href=\"https:\/\/www.linkedin.com\/shareArticle?mini=true&#038;url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F10494&#038;title=pg_dirtyread%20o%C3%B9%20comment%20r%C3%A9parer%20facilement%20un%20delete%20sauvage\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"linkedin\" title=\"Share on Linkedin\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/linkedin.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-mail nolightbox\" data-provider=\"mail\" rel=\"nofollow\" title=\"Share by email\" href=\"mailto:?subject=pg_dirtyread%20o%C3%B9%20comment%20r%C3%A9parer%20facilement%20un%20delete%20sauvage&#038;body=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20:%20https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F10494\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"mail\" title=\"Share by email\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/mail.png\" \/><\/a><p>Imaginez le sc\u00e9nario : nous sommes vendredi soir, en fin de journ\u00e9e, et pour une raison quelconque, un d\u00e9veloppeur qui a eu une semaine fatiguante se dit qu&#8217;il serait bien de supprimer les lignes qu&#8217;il a modifi\u00e9es dans la base de donn\u00e9es de d\u00e9veloppement, afin que lundi il puisse reprendre le travail \u00e0 z\u00e9ro. Il se connecte donc et, \u00e0 l&#8217;aide d&#8217;une commande de suppression sur la table concern\u00e9e, il efface ses quelques lignes&#8230; Avant de se rendre compte qu&#8217;il vient de le faire en production. <\/p>\n<p>Cela nous est arriv\u00e9 \u00e0 tous, au moins une fois dans notre carri\u00e8re. Un manque d&#8217;attention, une absence de s\u00e9curisation, une erreur est si vite arriv\u00e9e. Oui, mais voil\u00e0. La solution pour pallier \u00e0 ce genre de probl\u00e8mes, c&#8217;est g\u00e9n\u00e9ralement de recharger une sauvegarde de la base de donn\u00e9es, pour ne surtout pas perdre cette ligne essentielle des paiements enregistr\u00e9s&#8230; C&#8217;est long. La base est volumineuse&#8230; Et puis, nous n&#8217;avons pas un plan de sauvegarde fiable&#8230; Au secours !<\/p>\n<p>Avant de c\u00e9der \u00e0 la panique, peut-\u00eatre existe-t-il une autre solution \u00e0 votre probl\u00e8me.<\/p>\n<p>L&#8217;extension pg_dirtyread pourrait \u00eatre une id\u00e9e. Cette extension permet aux utilisateurs de lire des donn\u00e9es supprim\u00e9es dans les tables, ce qui est normalement impossible en temps normal. Cette extension est disponible gratuitement sur GIT, et elle peut vous sauver la vie dans le sc\u00e9nario \u00e9voqu\u00e9 juste avant. Nous allons voir ensemble comment l&#8217;utiliser :<\/p>\n<h2>Installer PostgreSQL et pg_dirtyread :<\/h2>\n<p>C&#8217;est assez rare pour le souligner, mais pg_dirtyread poss\u00e8de son propre package Ubuntu tout inclus. Ce package, si vous pouvez vous en servir, contient l&#8217;installation du moteur, l&#8217;installation des d\u00e9pendances de d\u00e9veloppement de PostgreSQL, le client, et l&#8217;extension elle-m\u00eame. Cela simplifie grandement le travail. Vous n&#8217;avez qu&#8217;\u00e0 t\u00e9l\u00e9charger le package dans la version qui vous int\u00e9resse. Pour cet article, j&#8217;ai choisi de t\u00e9l\u00e9charger et installer la derni\u00e8re version de PostgreSQL ainsi que la derni\u00e8re version de l&#8217;extension.<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\"> root:~\/pg_dirtyread# sudo apt -y install postgresql-16-dirtyread\r\nReading package lists... Done\r\nBuilding dependency tree... Done\r\nReading state information... Done\r\nThe following additional packages will be installed:\r\n  libcommon-sense-perl libjson-perl libjson-xs-perl libpq5 libsensors-config libsensors5 libtypes-serialiser-perl postgresql-16 postgresql-client-16 postgresql-client-common postgresql-common ssl-cert sysstat\r\nSuggested packages:\r\n  lm-sensors postgresql-doc-16 isag\r\nThe following NEW packages will be installed:\r\n  libcommon-sense-perl libjson-perl libjson-xs-perl libpq5 libsensors-config libsensors5 libtypes-serialiser-perl postgresql-16 postgresql-16-dirtyread postgresql-client-16 postgresql-client-common postgresql-common ssl-cert sysstat\r\n0 upgraded, 14 newly installed, 0 to remove and 0 not upgraded.\r\nNeed to get 21.3 MB of archives.\r\n...\r\nRunning kernel seems to be up-to-date.\r\n\r\nNo services need to be restarted.\r\n\r\nNo containers need to be restarted.\r\n\r\nNo user sessions are running outdated binaries.\r\n\r\nNo VM guests are running outdated hypervisor (qemu) binaries on this host.<\/pre>\n<p>Il existe une autre m\u00e9thode d&#8217;installation, la plus classique. Il suffit de t\u00e9l\u00e9charger les sources depuis le d\u00e9p\u00f4t GIT et de les compiler sur votre machine en utilisant les commandes &#8216;make&#8217; et &#8216;make install&#8217;.<\/p>\n<h2>Mise en place d&#8217;un environnement :<\/h2>\n<p>Pour notre test, j&#8217;ai choisit de me servir encore une fois de la base de donn\u00e9es dvdrental, accessible \u00e0 tous. Il me faut donc la t\u00e9l\u00e9charger :<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\"> postgres:~$ wget https:\/\/www.postgresqltutorial.com\/wp-content\/uploads\/2019\/05\/dvdrental.zip\r\n--2024-03-11 08:34:54--  https:\/\/www.postgresqltutorial.com\/wp-content\/uploads\/2019\/05\/dvdrental.zip\r\nResolving www.postgresqltutorial.com (www.postgresqltutorial.com)... 104.21.2.174, 172.67.129.129, 2606:4700:3037::6815:2ae, ...\r\nConnecting to www.postgresqltutorial.com (www.postgresqltutorial.com)|104.21.2.174|:443... connected.\r\nHTTP request sent, awaiting response... 200 OK\r\nLength: 550906 (538K) [application\/zip]\r\nSaving to: \u2018dvdrental.zip\u2019\r\n\r\ndvdrental.zip                                               100%[========================================================================================================================================&gt;] 537.99K  --.-KB\/s    in 0.01s\r\n\r\n2024-03-11 08:34:54 (46.0 MB\/s) - \u2018dvdrental.zip\u2019 saved [550906\/550906]  <\/pre>\n<p>Une fois t\u00e9l\u00e9charg\u00e9e, on la dezippe :<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">postgres:~$ ls -l\r\ntotal 544\r\ndrwxr-xr-x 3 postgres postgres   4096 Mar 11 08:30 16\r\n-rw-rw-r-- 1 postgres postgres 550906 May 12  2019 dvdrental.zip\r\npostgres:~$ unzip dvdrental.zip\r\nArchive:  dvdrental.zip\r\n  inflating: dvdrental.tar\r\npostgres:~$ ls -l\r\ntotal 3316\r\ndrwxr-xr-x 3 postgres postgres    4096 Mar 11 08:30 16\r\n-rw-rw-r-- 1 postgres postgres 2835456 May 12  2019 dvdrental.tar\r\n-rw-rw-r-- 1 postgres postgres  550906 May 12  2019 dvdrental.zip<\/pre>\n<p>On cr\u00e9\u00e9 la base de donn\u00e9es pour accueillir nos donn\u00e9es, et on charge le fichier de sauvegarde :<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">postgres:~$ psql\r\npsql (16.2 (Ubuntu 16.2-1.pgdg22.04+1))\r\nType &quot;help&quot; for help. <\/pre>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">postgres=# create database dvdrental;\r\nCREATE DATABASE\r\npostgres=# \\l\r\n                                                   List of databases\r\n   Name    |  Owner   | Encoding | Locale Provider | Collate |  Ctype  | ICU Locale | ICU Rules |   Access privileges\r\n-----------+----------+----------+-----------------+---------+---------+------------+-----------+-----------------------\r\n dvdrental | postgres | UTF8     | libc            | C.UTF-8 | C.UTF-8 |            |           |\r\n postgres  | postgres | UTF8     | libc            | C.UTF-8 | C.UTF-8 |            |           |\r\n template0 | postgres | UTF8     | libc            | C.UTF-8 | C.UTF-8 |            |           | =c\/postgres          +\r\n           |          |          |                 |         |         |            |           | postgres=CTc\/postgres\r\n template1 | postgres | UTF8     | libc            | C.UTF-8 | C.UTF-8 |            |           | =c\/postgres          +\r\n           |          |          |                 |         |         |            |           | postgres=CTc\/postgres\r\n(4 rows)<\/pre>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">postgres:~$ pg_restore -U postgres -d dvdrental dvdrental.tar<\/pre>\n<p>Une fois que c&#8217;est fait, on peut se connecter pour v\u00e9rifier que tout a bien \u00e9t\u00e9 charg\u00e9 :<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">postgres:~$ psql\r\npsql (16.2 (Ubuntu 16.2-1.pgdg22.04+1))\r\nType &quot;help&quot; for help.\r\n<\/pre>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">postgres=# \\c dvdrental\r\nYou are now connected to database &quot;dvdrental&quot; as user &quot;postgres&quot;.\r\ndvdrental=# \\dt\r\n             List of relations\r\n Schema |     Name      | Type  |  Owner\r\n--------+---------------+-------+----------\r\n public | actor         | table | postgres\r\n public | address       | table | postgres\r\n public | category      | table | postgres\r\n public | city          | table | postgres\r\n public | country       | table | postgres\r\n public | customer      | table | postgres\r\n public | film          | table | postgres\r\n public | film_actor    | table | postgres\r\n public | film_category | table | postgres\r\n public | inventory     | table | postgres\r\n public | language      | table | postgres\r\n public | payment       | table | postgres\r\n public | rental        | table | postgres\r\n public | staff         | table | postgres\r\n public | store         | table | postgres\r\n(15 rows)\r\n<\/pre>\n<h2>Premier sc\u00e9nario : Suppression de lignes dans une table<\/h2>\n<p>Prenons ici le cas de la situation d\u00e9crite dans l&#8217;introduction. Une ou plusieurs lignes ont \u00e9t\u00e9 supprim\u00e9es d&#8217;une ou plusieurs tables. Recharger l&#8217;int\u00e9gralit\u00e9 d&#8217;une base de donn\u00e9es juste pour ces quelques lignes, aussi essentielles soient-elles, demande un investissement \u00e9norme.<\/p>\n<p>Pour notre exemple, je vais supprimer un certain nombre de lignes de la table &#8216;payment&#8217;.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">dvdrental=# select * from payment limit 10;\r\n payment_id | customer_id | staff_id | rental_id | amount |        payment_date\r\n------------+-------------+----------+-----------+--------+----------------------------\r\n      17503 |         341 |        2 |      1520 |   7.99 | 2007-02-15 22:25:46.996577\r\n      17504 |         341 |        1 |      1778 |   1.99 | 2007-02-16 17:23:14.996577\r\n      17505 |         341 |        1 |      1849 |   7.99 | 2007-02-16 22:41:45.996577\r\n      17506 |         341 |        2 |      2829 |   2.99 | 2007-02-19 19:39:56.996577\r\n      17507 |         341 |        2 |      3130 |   7.99 | 2007-02-20 17:31:48.996577\r\n      17508 |         341 |        1 |      3382 |   5.99 | 2007-02-21 12:33:49.996577\r\n      17509 |         342 |        2 |      2190 |   5.99 | 2007-02-17 23:58:17.996577\r\n      17510 |         342 |        1 |      2914 |   5.99 | 2007-02-20 02:11:44.996577\r\n      17511 |         342 |        1 |      3081 |   2.99 | 2007-02-20 13:57:39.996577\r\n      17512 |         343 |        2 |      1547 |   4.99 | 2007-02-16 00:10:50.996577\r\n(10 rows)\r\n\r\ndvdrental=# delete from payment where payment_id between 17523 and 17532;\r\nDELETE 10<\/pre>\n<div class=\"flex-1 overflow-hidden\">\n<div class=\"react-scroll-to-bottom--css-toqmf-79elbk h-full\">\n<div class=\"react-scroll-to-bottom--css-toqmf-1n7m0yu\">\n<div class=\"flex flex-col text-sm pb-9\">\n<div class=\"w-full text-token-text-primary\" data-testid=\"conversation-turn-17\">\n<div class=\"px-4 py-2 justify-center text-base md:gap-6 m-auto\">\n<div class=\"flex flex-1 text-base mx-auto gap-3 md:px-5 lg:px-1 xl:px-5 md:max-w-3xl lg:max-w-[40rem] xl:max-w-[48rem] group final-completion\">\n<div class=\"relative flex w-full flex-col agent-turn\">\n<div class=\"flex-col gap-1 md:gap-3\">\n<div class=\"flex flex-grow flex-col max-w-full\">\n<div class=\"min-h-[20px] text-message flex flex-col items-start gap-3 whitespace-pre-wrap break-words [.text-message+&amp;]:mt-5 overflow-x-auto\" data-message-author-role=\"assistant\" data-message-id=\"107c8c40-0671-4f34-88f1-895d9fe2648b\">\n<div class=\"markdown prose w-full break-words dark:prose-invert light\">\n<p>La b\u00eatise est faite, les donn\u00e9es ont disparu. Lorsque j&#8217;essaie de les requ\u00eater pour voir si elles sont encore l\u00e0, je me heurte \u00e0 la r\u00e9alit\u00e9 : elles ont \u00e9t\u00e9 supprim\u00e9es.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">dvdrental=# select * from payment where payment_id between 17523 and 17532;\r\n payment_id | customer_id | staff_id | rental_id | amount | payment_date\r\n------------+-------------+----------+-----------+--------+--------------\r\n(0 rows)<\/pre>\n<p>La premi\u00e8re chose \u00e0 faire, en toute urgence, c&#8217;est de d\u00e9sactiver l&#8217;auto-vacuum. C&#8217;est votre pire ennemi dans notre sc\u00e9nario. C&#8217;est m\u00eame la premi\u00e8re chose \u00e0 faire lorsque vous vous rendez compte que l&#8217;erreur a \u00e9t\u00e9 commise :<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">dvdrental=# alter table payment set (autovacuum_enabled=false);<\/pre>\n<p>Si l&#8217;auto-vacuum est pass\u00e9 sur la table avant que vous n&#8217;ayez eu le temps de le d\u00e9sactiver, malheureusement, pg_dirtyread ne vous servira plus \u00e0 rien. Une fois cela fait, on initialise l&#8217;extension :<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">dvdrental=# CREATE EXTENSION pg_dirtyread;\r\nCREATE EXTENSION<\/pre>\n<p>L&#8217;extension \u00e9tant maintenant cr\u00e9\u00e9e, on peut requ\u00eater les donn\u00e9es perdues. La syntaxe d&#8217;utilisation exige que vous rappeliez le sch\u00e9ma de la table en question au moment de requ\u00eater les lignes supprim\u00e9es. Vous pouvez choisir de ne pas inclure toutes les colonnes, ou m\u00eame d&#8217;en ajouter, comme nous le verrons \u00e0 la fin de l&#8217;article. Dans notre exemple, la requ\u00eate pour consulter les donn\u00e9es effac\u00e9es sera la suivante :<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">dvdrental=# select * from pg_dirtyread('payment') AS t(payment_id integer, customer_id smallint, staff_id smallint, rental_id integer, amount numeric(5,2), payment_date timestamp without time zone);\r\n payment_id | customer_id | staff_id | rental_id | amount |        payment_date\r\n------------+-------------+----------+-----------+--------+----------------------------\r\n      17523 |         345 |        1 |      1457 |   4.99 | 2007-02-15 18:34:15.996577\r\n      17524 |         345 |        2 |      1550 |   0.99 | 2007-02-16 00:27:01.996577\r\n      17525 |         345 |        2 |      2766 |   4.99 | 2007-02-19 16:13:41.996577\r\n      17526 |         346 |        1 |      1994 |   5.99 | 2007-02-17 09:35:32.996577\r\n      17527 |         346 |        2 |      3372 |   2.99 | 2007-02-21 12:02:45.996577\r\n      17528 |         346 |        1 |      3421 |   2.99 | 2007-02-21 15:51:24.996577\r\n      17529 |         347 |        2 |      1711 |   8.99 | 2007-02-16 12:40:18.996577\r\n      17530 |         347 |        2 |      2274 |   0.99 | 2007-02-18 04:59:41.996577\r\n      17531 |         347 |        1 |      3026 |   4.99 | 2007-02-20 10:16:26.996577\r\n      17532 |         347 |        1 |      3092 |   8.99 | 2007-02-20 14:33:08.996577\r\n      17533 |         347 |        1 |      3326 |   7.99 | 2007-02-21 07:33:16.996577\r\n      17534 |         348 |        1 |      1654 |   2.99 | 2007-02-16 08:11:14.996577\r\n      17535 |         348 |        1 |      2041 |   8.99 | 2007-02-17 12:47:26.996577\r\n      17536 |         348 |        2 |      2499 |   0.99 | 2007-02-18 21:30:02.996577<\/pre>\n<p>On voit bien appara\u00eetre en d\u00e9but de liste nos lignes qui sont cens\u00e9es ne plus exister. Cela nous permet \u00e9ventuellement d&#8217;extraire les donn\u00e9es qu&#8217;elles contiennent pour pouvoir les r\u00e9injecter ensuite avec un INSERT. On peut \u00e9galement filtrer les donn\u00e9es pour ne rechercher que celles que l&#8217;on a supprim\u00e9es :<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">dvdrental=# select * from pg_dirtyread('payment') payment(payment_id integer, customer_id smallint, staff_id smallint, rental_id integer, amount numeric(5,2), dropped_6 timestamp without time zone) where payment_id = 17523;\r\n payment_id | customer_id | staff_id | rental_id | amount |         dropped_6\r\n------------+-------------+----------+-----------+--------+----------------------------\r\n      17523 |         345 |        1 |      1457 |   4.99 | 2007-02-15 18:34:15.996577\r\n(1 row)\r\n<\/pre>\n<h2>Deuxi\u00e8me sc\u00e9nario : On a supprim\u00e9 une colonne enti\u00e8re<\/h2>\n<p>Deuxi\u00e8me cas typique, s\u00fbrement plus rare, celui o\u00f9 une colonne enti\u00e8re est supprim\u00e9e. Pour notre exemple, je vais supprimer la colonne contenant la date de paiement :<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">dvdrental=# alter table payment drop column payment_date;\r\nALTER TABLE<\/pre>\n<p>pg_dirtyread nous permet de retrouver les informations de cette colonne \u00e0 condition qu&#8217;aucun VACUUM FULL ou CLUSTER n&#8217;ait \u00e9t\u00e9 ex\u00e9cut\u00e9. Pour ce faire, il faut conna\u00eetre la position de la colonne dans l&#8217;ordre des colonnes de la table. Pour notre exemple, la colonne de date est la derni\u00e8re colonne de la table, donc en position 6. Pour retrouver nos donn\u00e9es, on peut donc ex\u00e9cuter la commande suivante :<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">dvdrental=# select * from pg_dirtyread('payment') payment(payment_id integer, customer_id smallint, staff_id smallint, rental_id integer, amount numeric(5,2), dropped_6 timestamp without time zone);\r\n payment_id | customer_id | staff_id | rental_id | amount |         dropped_6\r\n------------+-------------+----------+-----------+--------+----------------------------\r\n      17523 |         345 |        1 |      1457 |   4.99 | 2007-02-15 18:34:15.996577\r\n      17524 |         345 |        2 |      1550 |   0.99 | 2007-02-16 00:27:01.996577\r\n      17525 |         345 |        2 |      2766 |   4.99 | 2007-02-19 16:13:41.996577\r\n      17526 |         346 |        1 |      1994 |   5.99 | 2007-02-17 09:35:32.996577\r\n      17527 |         346 |        2 |      3372 |   2.99 | 2007-02-21 12:02:45.996577\r\n<\/pre>\n<p>Le cas d&#8217;une restauration d&#8217;une colonne enti\u00e8re supprim\u00e9e est compliqu\u00e9 \u00e0 g\u00e9rer. Il faudrait la recr\u00e9er, puis modifier toutes les lignes une \u00e0 une pour r\u00e9ajouter les valeurs de cette fameuse colonne. Cela peut s&#8217;av\u00e9rer un peu complexe \u00e0 r\u00e9aliser. Cependant, si vous ne disposez pas d&#8217;une sauvegarde pg_dump, vous n&#8217;aurez peut-\u00eatre pas d&#8217;autres alternatives que cela, \u00e0 part recharger enti\u00e8rement la base.<\/p>\n<h2>Bonus : R\u00e9cup\u00e9rer les informations syst\u00e8me des lignes supprim\u00e9es<\/h2>\n<p>Avec pg_dirtyread, il est possible de r\u00e9cup\u00e9rer les informations syst\u00e8me des lignes qui ont \u00e9t\u00e9 supprim\u00e9es. Pour ce faire, rien de plus simple : il suffit d&#8217;indiquer dans la requ\u00eate les informations que vous souhaitez r\u00e9cup\u00e9rer. De plus, il existe une colonne qui indique si la ligne est suppos\u00e9ment supprim\u00e9e ou non, ce qui pourrait \u00eatre pratique pour trier les diff\u00e9rentes lignes selon leur \u00e9tat :<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">dvdrental=#  SELECT * FROM pg_dirtyread('payment') AS t(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean);\r\n tableoid |   ctid    | xmin | xmax | cmin | cmax | dead\r\n----------+-----------+------+------+------+------+------\r\n    16505 | (0,21)    |  835 |  941 |    0 |    0 | f\r\n    16505 | (0,22)    |  835 |  941 |    0 |    0 | f\r\n    16505 | (0,23)    |  835 |  941 |    0 |    0 | f\r\n    16505 | (0,24)    |  835 |  941 |    0 |    0 | f\r\n    16505 | (0,25)    |  835 |  941 |    0 |    0 | f\r\n    16505 | (0,26)    |  835 |  941 |    0 |    0 | f\r\n    16505 | (0,27)    |  835 |  941 |    0 |    0 | f\r\n    16505 | (0,28)    |  835 |  941 |    0 |    0 | f\r\n    16505 | (0,29)    |  835 |  941 |    0 |    0 | f\r\n    16505 | (0,30)    |  835 |  941 |    0 |    0 | f\r\n<\/pre>\n<h2>Conclusion :<\/h2>\n<p>En conclusion, l&#8217;extension pg_dirtyread offre une solution pr\u00e9cieuse pour acc\u00e9der aux donn\u00e9es supprim\u00e9es dans une base de donn\u00e9es PostgreSQL. Son utilisation peut \u00eatre cruciale dans des cas d&#8217;incidents critiques tels que la r\u00e9cup\u00e9ration de donn\u00e9es perdues accidentellement ou la r\u00e9solution d&#8217;incoh\u00e9rences de donn\u00e9es. Cependant, il est essentiel de rappeler que son application reste extr\u00eamement situationnelle et que pour qu&#8217;elle puisse \u00eatre efficace, l&#8217;autovacuum doit \u00eatre d\u00e9sactiv\u00e9, ce qui n&#8217;est pas forc\u00e9ment recommand\u00e9.<\/p>\n<a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-twitter nolightbox\" data-provider=\"twitter\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Twitter\" href=\"https:\/\/twitter.com\/intent\/tweet?url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F10494&#038;text=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"twitter\" title=\"Share on Twitter\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/twitter.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-linkedin nolightbox\" data-provider=\"linkedin\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Linkedin\" href=\"https:\/\/www.linkedin.com\/shareArticle?mini=true&#038;url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F10494&#038;title=pg_dirtyread%20o%C3%B9%20comment%20r%C3%A9parer%20facilement%20un%20delete%20sauvage\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"linkedin\" title=\"Share on Linkedin\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/linkedin.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-mail nolightbox\" data-provider=\"mail\" rel=\"nofollow\" title=\"Share by email\" href=\"mailto:?subject=pg_dirtyread%20o%C3%B9%20comment%20r%C3%A9parer%20facilement%20un%20delete%20sauvage&#038;body=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20:%20https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F10494\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"mail\" title=\"Share by email\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/mail.png\" \/><\/a>","protected":false},"excerpt":{"rendered":"<p>Imaginez le sc\u00e9nario : nous sommes vendredi soir, en fin de journ\u00e9e, et pour une raison quelconque, un d\u00e9veloppeur qui a eu une semaine fatiguante se dit qu&#8217;il serait bien de supprimer les lignes qu&#8217;il a modifi\u00e9es dans la base&hellip; <a href=\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/\" class=\"more-link\">Continuer la lecture <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":41,"featured_media":10501,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[266],"tags":[479,431],"class_list":["post-10494","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-postgresql","tag-pg_dirtyread","tag-postgresql"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v20.8 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>pg_dirtyread o\u00f9 comment r\u00e9parer facilement un delete sauvage - Capdata TECH BLOG<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/\" \/>\n<meta property=\"og:locale\" content=\"fr_FR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"pg_dirtyread o\u00f9 comment r\u00e9parer facilement un delete sauvage - Capdata TECH BLOG\" \/>\n<meta property=\"og:description\" content=\"Imaginez le sc\u00e9nario : nous sommes vendredi soir, en fin de journ\u00e9e, et pour une raison quelconque, un d\u00e9veloppeur qui a eu une semaine fatiguante se dit qu&#8217;il serait bien de supprimer les lignes qu&#8217;il a modifi\u00e9es dans la base&hellip; Continuer la lecture &rarr;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/\" \/>\n<meta property=\"og:site_name\" content=\"Capdata TECH BLOG\" \/>\n<meta property=\"article:published_time\" content=\"2024-03-27T14:24:14+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2024\/03\/istockphoto-464515667-612x612-1.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"612\" \/>\n\t<meta property=\"og:image:height\" content=\"405\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Sarah FAVEERE\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u00c9crit par\" \/>\n\t<meta name=\"twitter:data1\" content=\"Sarah FAVEERE\" \/>\n\t<meta name=\"twitter:label2\" content=\"Dur\u00e9e de lecture estim\u00e9e\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/\"},\"author\":{\"name\":\"Sarah FAVEERE\",\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/person\/686f2452f7ec79115d31e41c230a9da2\"},\"headline\":\"pg_dirtyread o\u00f9 comment r\u00e9parer facilement un delete sauvage\",\"datePublished\":\"2024-03-27T14:24:14+00:00\",\"dateModified\":\"2024-03-27T14:24:14+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/\"},\"wordCount\":1923,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/blog.capdata.fr\/#organization\"},\"keywords\":[\"pg_dirtyread\",\"PostgreSQL\"],\"articleSection\":[\"PostgreSQL\"],\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/\",\"url\":\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/\",\"name\":\"pg_dirtyread o\u00f9 comment r\u00e9parer facilement un delete sauvage - Capdata TECH BLOG\",\"isPartOf\":{\"@id\":\"https:\/\/blog.capdata.fr\/#website\"},\"datePublished\":\"2024-03-27T14:24:14+00:00\",\"dateModified\":\"2024-03-27T14:24:14+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/#breadcrumb\"},\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/blog.capdata.fr\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"pg_dirtyread o\u00f9 comment r\u00e9parer facilement un delete sauvage\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.capdata.fr\/#website\",\"url\":\"https:\/\/blog.capdata.fr\/\",\"name\":\"Capdata TECH BLOG\",\"description\":\"Le blog technique sur les bases de donn\u00e9es de CAP DATA Consulting\",\"publisher\":{\"@id\":\"https:\/\/blog.capdata.fr\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.capdata.fr\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"fr-FR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/blog.capdata.fr\/#organization\",\"name\":\"Capdata TECH BLOG\",\"url\":\"https:\/\/blog.capdata.fr\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp\",\"contentUrl\":\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp\",\"width\":800,\"height\":254,\"caption\":\"Capdata TECH BLOG\"},\"image\":{\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.linkedin.com\/company\/cap-data-consulting\/mycompany\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/person\/686f2452f7ec79115d31e41c230a9da2\",\"name\":\"Sarah FAVEERE\",\"sameAs\":[\"http:\/\/blog.capdata.fr\"],\"url\":\"https:\/\/blog.capdata.fr\/index.php\/author\/sfaveere\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"pg_dirtyread o\u00f9 comment r\u00e9parer facilement un delete sauvage - Capdata TECH BLOG","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/","og_locale":"fr_FR","og_type":"article","og_title":"pg_dirtyread o\u00f9 comment r\u00e9parer facilement un delete sauvage - Capdata TECH BLOG","og_description":"Imaginez le sc\u00e9nario : nous sommes vendredi soir, en fin de journ\u00e9e, et pour une raison quelconque, un d\u00e9veloppeur qui a eu une semaine fatiguante se dit qu&#8217;il serait bien de supprimer les lignes qu&#8217;il a modifi\u00e9es dans la base&hellip; Continuer la lecture &rarr;","og_url":"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/","og_site_name":"Capdata TECH BLOG","article_published_time":"2024-03-27T14:24:14+00:00","og_image":[{"width":612,"height":405,"url":"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2024\/03\/istockphoto-464515667-612x612-1.jpg","type":"image\/jpeg"}],"author":"Sarah FAVEERE","twitter_card":"summary_large_image","twitter_misc":{"\u00c9crit par":"Sarah FAVEERE","Dur\u00e9e de lecture estim\u00e9e":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/#article","isPartOf":{"@id":"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/"},"author":{"name":"Sarah FAVEERE","@id":"https:\/\/blog.capdata.fr\/#\/schema\/person\/686f2452f7ec79115d31e41c230a9da2"},"headline":"pg_dirtyread o\u00f9 comment r\u00e9parer facilement un delete sauvage","datePublished":"2024-03-27T14:24:14+00:00","dateModified":"2024-03-27T14:24:14+00:00","mainEntityOfPage":{"@id":"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/"},"wordCount":1923,"commentCount":0,"publisher":{"@id":"https:\/\/blog.capdata.fr\/#organization"},"keywords":["pg_dirtyread","PostgreSQL"],"articleSection":["PostgreSQL"],"inLanguage":"fr-FR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/","url":"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/","name":"pg_dirtyread o\u00f9 comment r\u00e9parer facilement un delete sauvage - Capdata TECH BLOG","isPartOf":{"@id":"https:\/\/blog.capdata.fr\/#website"},"datePublished":"2024-03-27T14:24:14+00:00","dateModified":"2024-03-27T14:24:14+00:00","breadcrumb":{"@id":"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/#breadcrumb"},"inLanguage":"fr-FR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.capdata.fr\/index.php\/pg_dirtyread-ou-comment-reparer-facilement-un-delete-sauvage\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/blog.capdata.fr\/"},{"@type":"ListItem","position":2,"name":"pg_dirtyread o\u00f9 comment r\u00e9parer facilement un delete sauvage"}]},{"@type":"WebSite","@id":"https:\/\/blog.capdata.fr\/#website","url":"https:\/\/blog.capdata.fr\/","name":"Capdata TECH BLOG","description":"Le blog technique sur les bases de donn\u00e9es de CAP DATA Consulting","publisher":{"@id":"https:\/\/blog.capdata.fr\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.capdata.fr\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"fr-FR"},{"@type":"Organization","@id":"https:\/\/blog.capdata.fr\/#organization","name":"Capdata TECH BLOG","url":"https:\/\/blog.capdata.fr\/","logo":{"@type":"ImageObject","inLanguage":"fr-FR","@id":"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/","url":"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp","contentUrl":"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp","width":800,"height":254,"caption":"Capdata TECH BLOG"},"image":{"@id":"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.linkedin.com\/company\/cap-data-consulting\/mycompany\/"]},{"@type":"Person","@id":"https:\/\/blog.capdata.fr\/#\/schema\/person\/686f2452f7ec79115d31e41c230a9da2","name":"Sarah FAVEERE","sameAs":["http:\/\/blog.capdata.fr"],"url":"https:\/\/blog.capdata.fr\/index.php\/author\/sfaveere\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts\/10494","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/comments?post=10494"}],"version-history":[{"count":9,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts\/10494\/revisions"}],"predecessor-version":[{"id":10555,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts\/10494\/revisions\/10555"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/media\/10501"}],"wp:attachment":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/media?parent=10494"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/categories?post=10494"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/tags?post=10494"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}