PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment conserver l'historique des modifications d'un champ de chaîne volumineux dans une base de données relationnelle

Une solution sur laquelle je travaille actuellement, qui fonctionne bien jusqu'à présent, implémente la conception que j'ai proposée dans la question

Je vais partager les détails de ma mise en œuvre ici

Pour créer des deltas et utiliser pour reconstruire le texte intégral, j'utilise le fantastique bibliothèque google-diff-match-patch . Vous pouvez lire la documentation de l'API indépendante de l'implémentation pour mieux comprendre les exemples de code ci-dessous, même si c'est quand même assez lisible.

google-diff-match-patch a des implémentations Java et JS afin que je puisse l'utiliser pour calculer les deltas avec Java sur le serveur. J'ai choisi de convertir chaque delta en une chaîne à la fois pour qu'il puisse être facilement stocké dans la base de données et facilement consommé par la bibliothèque JS sur le client. Plus d'informations ci-dessous.

public String getBackwardsDelta(String editedBlogPost, String existingBlogPost) {
    diff_match_patch dmp = new diff_match_patch();
    LinkedList<diff_match_patch.Patch> patches = 
        dmp.patch_make(editedBlogPost, existingBlogPost);
    return dmp.patch_toText(patches);
}

N.B. il m'a fallu un certain temps pour comprendre comment supprimer la version officielle de google-diff-match-patch en utilisant maven. Ce n'est pas dans le dépôt central maven, mais sur leur propre dépôt sur googlecode.com. Juste pour noter, certaines personnes l'ont forké et ont mis leurs versions fourchues dans maven central, mais si vous voulez vraiment la version officielle, vous pouvez l'obtenir en ajoutant le dépôt et la dépendance dans votre pom.xml comme suit

<repository>
  <id>google-diff-patch-match</id>
  <name>google-diff-patch-match</name>
  <url>https://google-diff-match-patch.googlecode.com/svn/trunk/maven/</url>
</repository>

<dependency>
  <groupId>diff_match_patch</groupId>
  <artifactId>diff_match_patch</artifactId>
  <version>current</version>
</dependency>

Pour le front-end, je transmets le texte intégral du dernier article de blog, ainsi qu'une chaîne de deltas remontant dans le temps représentant chaque modification, puis je reconstruis le texte intégral de chaque version dans le navigateur en JS.

Pour obtenir la bibliothèque, j'utilise npm + browserify. La bibliothèque est disponible sur npm comme diff-match-patch . La version 1.0.0 est la seule version.

getTextFromDelta: function(originalText, delta) {
  var DMP = require('diff-match-patch'); // get the constructor function
  var dmp = new DMP();
  var patches = dmp.patch_fromText(delta);
  return dmp.patch_apply(patches, originalText)[0];
}

Et voilà, ça marche à merveille.

En termes de stockage des modifications des articles de blog, j'utilise simplement une table BLOG_POST_EDITS où je stocke l'identifiant de l'article de blog, un horodatage du moment où la modification a été effectuée (que j'utiliserai plus tard pour ordonner correctement les modifications afin de créer la chaîne lors de la reconstruction des versions en texte intégral sur le client), et le delta arrière entre le live actuel article de blog dans le BLOG_POST tableau et la version modifiée entrante de l'article de blog.

J'ai choisi de stocker une "chaîne" de deltas car cela convient bien à mon cas d'utilisation et est plus simple côté code serveur. Cela signifie que pour reconstruire la version M de N, je dois renvoyer au client une chaîne de deltas N-(M-1) du texte intégral du blog en direct vers la version M. Mais dans mon cas d'utilisation, il se trouve que voulez envoyer toute la chaîne à chaque fois, de toute façon, donc ça va.

Pour une efficacité légèrement meilleure sur le fil pour demander des versions spécifiques, tous les deltas pourraient être recalculés à partir de la nouvelle version de publication de blog éditée vers chaque version (restaurée) chaque fois qu'une modification est effectuée, mais cela signifierait plus de travail et de complexité sur le serveur.