Usuwanie danych, zaraz po dodawaniu, odczycie i aktualizacji, jest jedną z czterech podstawowych czynności, jakie możemy w tradycyjnych aplikacjach. Wydawać by się mogło, że nie jest to zbyt ciekawy temat. Ot wydajemy polecenie „usuń”, a nasze dane bezpowrotnie znikają. Okazuje się jednak, że nawet tak trywialną czynność jak usuwanie danych można wykonać na kilka sposobów oraz otrzymać różne rezultaty! Jednym z bardzo ciekawych sposobów na „usuwanie” danych jest soft delete. O tym, dlaczego słowo usuwanie ująłem w cudzysłów, dowiesz się w dalszej części tego artykułu.
Na czym polega soft delete?
Mechanizm soft delete polega nie tyle na faktycznym usunięciu danych z bazy danych, ile na oznaczeniu ich jako usunięte. Najczęściej odbywa się to przez dodanie do rekordu w bazie odpowiedniej flagi. Dzięki temu nasze dane nadal pozostają w bazie danych, jednak z poziomu aplikacji są niewidoczne, tak jakby ich nie było. Korzystając z tego mechanizmu, otrzymujemy wiele nowych możliwości.
Przede wszystkim w przypadku gdy użytkownik nieumyślnie usunął swoje dane, możemy w bardzo prosty sposób je przywrócić. Nie ma wtedy potrzeby zaglądania do backupu (a co jeśli nie ma backupu?), dzięki czemu oszczędzamy czas i nerwy.
Zabezpieczamy się też przed sytuacją, gdy użytkownik umyślnie usunie dane, które nie chcemy, by były bezpowrotnie usunięte. Przykładem mogą być toksyczne zachowania na serwisach społecznościowych. Przykładowo użytkownik może opublikować niestosowne treści, a następnie je usunąć i liczyć na to, że będzie bezkarny. Korzystając z soft delete, widzimy każdy opublikowany wpis, nawet jeśli użytkownik usunie go chwilę po dodaniu.
Oprócz tego możemy wykorzystać usunięte dane do celów rozwoju aplikacji. Jeśli nasza aplikacja uczy się zachowań użytkowników, to nawet jeśli użytkownik zdecyduje się na usunięcie konta, to jego aktywność i tak może posłużyć jako kolejna próbka do uczenia się dla naszej aplikacji.
A co z wadami?
Soft delete w mojej opinii posiada dwie główne wady. Przede wszystkim magazynujemy dane, z których prawdopodobnie nigdy nie skorzystamy, przez co marnujemy powierzchnię dyskową. Istnieje bardzo mała szansa, że ktoś będzie chciał odzyskać swoje dane.
Drugą kwestią są kwestie prawne. Należy pamiętać, że zgodnie z prawem użytkownik ma prawo żądać faktycznego USUNIĘCIA danych na swój temat z bazy danych. W aplikacji, z której korzysta mała liczba użytkowników, nie stanowi to problemu, ponieważ można usunąć takie dane ręcznie. Problem zaczyna się pojawiać w dużych aplikacjach, gdzie takich zgłoszeń możemy otrzymywać setki. W takim wypadku, tak czy inaczej jesteśmy zmuszeni do stworzenia metod do klasycznego usuwania użytkowników.
Przejdźmy do praktyki
Działanie soft delete pokażę na przykładzie aplikacji napisanej w Node.js, Express.js i korzystającej z MongoDB. Wykorzystaną bibliotekę do komunikacji z bazą MongoDB jest mongoose
. Do obsłużenia mechanizmu soft delete wykorzystam paczkę mongoose-delete
.
Przede wszystkim na samym początku musimy zainstalować wspomnianą wcześniej paczkę. Następnie importujemy naszą paczkę do pliku z modelem. Potem używamy jej jako plugin.
import mongoose from 'mongoose';
import mongooseDelete from 'mongoose-delete';
const userSchema = mongoose.Schema({
name: {
type: String,
required: [true, 'Name field is required']
},
email: {
type: String,
unique: true,
trim: true,
lowercase: true,
required: [true, 'Email field is required.']
}
}, {
timestamps: true
});
userSchema.plugin(mongooseDelete);
module.exports = mongoose.model('User', userSchema, 'users');
Dodatkowe możliwości
Oprócz samego uruchomienia soft delete paczka daje kilka dodatkowych opcji. Jedną z nich jest możliwość dodania do rekordu timestampa z datą usunięcia (deletedAt
). Inną z możliwości jest dodanie informacji o tym, kto usunął dany rekord (deletedBy
). Dodatkowe parametry podajemy jako właściwości obiektu, który przekazujemy jako drugi argument metody plugin.
import mongoose from 'mongoose';
import mongooseDelete from 'mongoose-delete';
const userSchema = mongoose.Schema({
name: {
type: String,
required: [true, 'Name field is required']
},
email: {
type: String,
unique: true,
trim: true,
lowercase: true,
required: [true, 'Email field is required.']
}
}, {
timestamps: true
});
userSchema.plugin(mongooseDelete, { deletedAt: true, deletedBy: true, overrideMethods: true });
module.exports = mongoose.model('User', userSchema, 'users');
Jak pewnie zauważyłeś, oprócz właściwości, o których wspominałem, pojawiła się też właściwość overrideMethods
. Dzięki temu nadpisywane są domyślne metody mongoose
, tak aby nasz soft delete był w nich już zaimplementowany. Jeśli chcemy, aby nadpisane zostały tylko wybrane metody, możemy zamiast wartości true
przekazać tablicę z nazwami metod do nadpisania.
Sama paczka oferuje jeszcze kilka innych możliwości, takich jak np. tworzenie indeksów. Jeśli chcesz poznać 100% możliwości mongoose-delete
, to zajrzyj do źródeł na końcu wpisu. Tam znajdziesz link do prostej i przejrzystej dokumentacji.
Podsumowanie
Mam nadzieję, że nauczyłeś/aś się dzięki temu krótkiemu artykułowi czegoś nowego, co wykorzystasz w swoich projektach. Jak zwykle zachęcam do pozostawienia komentarza. Jeśli artykuł Ci się spodobał, to udostępnij go w mediach społecznościowych. Zachęcam też do zapoznania się ze źródłami.
Wszystko spoko, ale brakuje mi chyba najważniejszej informacji, że czasami wręcz musimy zastosować soft delete nawet wbrew woli użytkownika i to właśnie po to, aby spełnić wymogi prawa. Na przykład gdy prowadzisz stronę obsługującą płatności i masz obowiązek przetrzymywania pewnych danych przez okres np. 5 lat. Warto więc zawsze „żądania” userów przefiltrować przez realne przepisy prawa i dopiero wtedy podjąć decyzję 🙂
Racja, o tym nie pomyślałem, dzięki za uzupełnienie 🙂