github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/migration/v2_to_v3/cmd/remove_dup_doc/main.go (about) 1 // Recherche et supprime les documents 2 // en double, pour une même contrainte 3 // Les autres doublons doivent être géré manuellement. 4 package main 5 6 import ( 7 "bytes" 8 "database/sql" 9 "flag" 10 "fmt" 11 "log" 12 13 "github.com/benoitkugler/goACVE/logs" 14 "github.com/benoitkugler/goACVE/server/core/rawdata" 15 ) 16 17 func check(err error) { 18 if err != nil { 19 log.Fatal(err) 20 } 21 } 22 23 func main() { 24 dev := flag.Bool("dev", true, "which DB to use") 25 flag.Parse() 26 27 logsDB := logs.DBProd 28 if *dev { 29 logsDB = logs.DBDev 30 } 31 32 fmt.Println("Connecting on", logsDB.Host, logsDB.Name) 33 34 db, err := rawdata.ConnectDB(logsDB) 35 check(err) 36 defer db.Close() 37 38 liens, err := rawdata.SelectAllDocumentPersonnes(db) 39 check(err) 40 41 // on cherche les multi documents 42 type key struct { 43 IdContrainte, IdPersonne int64 44 } 45 46 crible := map[key]rawdata.DocumentPersonnes{} 47 for _, lien := range liens { 48 keyV := key{IdContrainte: lien.IdContrainte, IdPersonne: lien.IdPersonne} 49 crible[keyV] = append(crible[keyV], lien) 50 } 51 52 var docsToSupp rawdata.Ids 53 for _, docs := range crible { 54 if len(docs) > 1 { 55 paquets := searchDoublons(db, docs) 56 docsToSupp = append(docsToSupp, paquets.selectDocsToSupp()...) 57 } 58 } 59 fmt.Printf("Found %d doublons \n", len(docsToSupp)) 60 tx, err := db.Begin() 61 check(err) 62 _, err = rawdata.DeleteDocumentPersonnesByIdDocuments(tx, docsToSupp...) 63 if err != nil { 64 err = tx.Rollback() 65 log.Fatal(err) 66 } 67 _, err = rawdata.DeleteDocumentsByIds(tx, docsToSupp...) 68 if err != nil { 69 err = tx.Rollback() 70 log.Fatal(err) 71 } 72 err = tx.Commit() 73 check(err) 74 fmt.Println("Deleted.") 75 } 76 77 // stocke une partitions, non couvrante, d'ids 78 type doublons []rawdata.Set 79 80 // si idExistant n'est pas encore présent, un nouveau set le contenant est ajouté 81 func (d *doublons) getById(idExistant int64) rawdata.Set { 82 for _, paquet := range *d { 83 if paquet.Has(idExistant) { 84 return paquet 85 } 86 } 87 // on a pas trouvé l'id 88 newPaquet := rawdata.NewSet() 89 newPaquet.Add(idExistant) 90 *d = append(*d, newPaquet) 91 return newPaquet 92 } 93 94 // sélectionne tous les doublons sauf 1 (par paquet) 95 func (d doublons) selectDocsToSupp() rawdata.Ids { 96 var docsToSupp rawdata.Ids 97 for _, paquet := range d { 98 // paquet a forcément au moins 2 élements 99 docsToSupp = append(docsToSupp, paquet.Keys()[1:]...) 100 } 101 return docsToSupp 102 } 103 104 // parmi les documents donnés, charge et compare les contenus 105 func searchDoublons(db *sql.DB, docs rawdata.DocumentPersonnes) doublons { 106 // candidats pour des doublons 107 // ont-ils le même contenu ? 108 var docToLoad rawdata.Ids 109 for _, doc := range docs { 110 docToLoad = append(docToLoad, doc.IdDocument) 111 } 112 contenus, err := rawdata.SelectContenuDocumentsByIdDocuments(db, docToLoad...) 113 check(err) 114 var paquets doublons 115 for i, ci := range contenus { 116 for j, cj := range contenus { 117 if i == j { 118 // ne compare pas à soit même 119 continue 120 } 121 if bytes.Equal(ci.Contenu, cj.Contenu) { 122 // on a trouvé un doublon 123 // on l'ajoute au paquet i 124 paquet := paquets.getById(ci.IdDocument) 125 paquet.Add(cj.IdDocument) 126 } 127 } 128 } 129 return paquets 130 }