Seedery w Node.js - okładka

Seedery w Node.js

Opublikowano Kategorie Backend, JavaScriptCzas czytania 4min

Tworząc aplikację, bardzo często zachodzi potrzeba pracy na danych. Nie zawsze istnieje możliwość pracy na realnych danych. Oczywiście nic nie stoi na przeszkodzie, abyśmy uruchomili pokłady swojej wyobraźni i wpisywali do bazy danych testowe rekordy. Niemniej jednak jest to mało produktywne zajęcie. Nie wspominam nawet o tym, że takich rekordów często potrzeba dziesiątki, setki, a nawet i czasem tysiące. W tym miejscu z pomocą przychodzą seedery, czyli specjalne funkcje pozwalające nam na generowanie testowych danych.

Po raz pierwszy z seederami zetknąłem się podczas pracy z Laravelem. Tam cały proces generowania oraz uruchamiania seedera jest mocno zautomatyzowany i wbudowany w sam framework. Do utworzenia pliku oraz samego seedowania mamy gotowe polecenia i w praktyce jedyne co musimy podać to schemat danych, na którego podstawie zostaną one wygenerowane.

Seedery w Node.js - ziarna

A jak jest w Node?

W Node.js trzeba ogarnąć ten temat na własną rękę. Postanowiłem więc napisać własne rozwiązanie i przedstawić je w tym artykule, tak aby jednocześnie pochwalić się tym, co stworzyłem, ale także poddać to ocenie i weryfikacji. Do przygotowania rozwiązania wykorzystałem bibliotekę mongoose oraz bazę dokumentową MongoDB.

Krok po kroku

Pierwszym krokiem będzie stworzenie modelu. Na jego podstawie będę tworzył testowe dane i zamieszczał je w bazie danych. Drugim krokiem jest stworzenie wcześniej omawianego seedera. Na początku tworzę wykonać połączenie z bazą danych. Sam seeder w naszym przypadku nie jest integralną częścią aplikacji, dlatego zdecydowałem się na osobne połączenie. Następnie tworzę obiekt będący reprezentacją naszych danych testowych. Kolejnym krokiem jest użycie na obiekcie z danymi metody save oraz zamknięcie połączenia z bazą danych.


import mongoose from 'mongoose';
import Message from '../models/Message';

mongoose.connect( 'mongodb://localhost:27017/db-url', { useNewUrlParser: true } );

const message = new Message({
    message: 'Hello World!'
});

message.save().then( () => mongoose.disconnect() );

Jest to rozwiązanie działające, jednak można dodać w nim kilka usprawnień.

Optymalizacja

Przede wszystkim warto dodać funkcję, która przed seedowaniem wyczyści kolekcję z pozostałości po poprzednim seedowaniu.

Kolejnym bardzo ułatwiającym życie elementem jest skorzystanie z Fakera. Faker to biblioteka służąca do generowania losowych, fałszywych danych. Za pomocą Fakera można wygenerować takie dane jak imiona, nazwiska, numery telefonu, adresy email itd.

Aby skorzystać z Fakera, należy go najpierw oczywiście dodać do projektu i zaimportować. Całą, obszerną listę możliwych do wygenerowania danych oraz sposób użycia samej biblioteki znajdziesz w dokumentacji. Po wykonaniu seedowania powinniśmy otrzymać komunikat o powodzeniu lub o błędzie. Poniższy przykład zawiera automatyczne seedowanie z wykorzystaniem Fakera.

import faker from 'faker';
import mongoose from 'mongoose';
import Message from '../models/Message';

mongoose.connect('mongodb://localhost:27017/db-url', { useNewUrlParser: true });
Message.deleteMany({}, err=> console.log(err));

const message = new Message({
    message: faker.lorem.sentence()
});
message.save()
    .then(() => mongoose.disconnect())
    .then(() => console.log('Message seed succesfully'))
    .catch(err => console.log(err));

Skalowalność

Ze skalowaniem ilości seedowanych danych nie ma żadnego problemu. Wystarczy stworzyć pętlę, która wykona się żądaną ilość razy.

Schody zaczynają się w momencie tworzenia kolejnych seederów. Nie ma problemu w ręcznym wykonaniu polecenia dla jednego bądź kilku seederów. Problem zaczyna się pojawiać w momencie, w którym tych seederów pojawi się znaczna ilość. Warto byłoby zoptymalizować również i ten proces. Do tego zadania posłuży nowy plik, w którym zamieszczę skrypt odpowiadający za uruchomienie wszystkich plików w zadanym katalogu.

import fs from 'fs';
import async from 'async';
const exec = require('child_process').exec

const scriptsFolder = './src/seed/';

const files = fs.readdirSync(scriptsFolder);
const funcs = files.map(function(file) {
    return exec.bind(null, `babel-node ${scriptsFolder}${file}`);
});

function getResults(err, data) {
    if (err) {
        return console.log(err);
    }
    const results = data.map(function(lines){
        return lines.join('');
    });
    console.log(results);
}

async.parallel(funcs, getResults);

Teraz jedyne co pozostaje to stworzyć odpowiednie polecenie w pliku package.json, które uruchomi nasz plik startujący nasze seedery. Po uruchomieniu, jeżeli wszystko zostało zrobione jak należy, w bazie danych powinny pojawić się nowe dokumenty.

Podsumowanie

Rozwiązanie przedstawione w tym wpisie nie jest w 100% idealne. Występuje np. problem z referencjami do zasobów. Niemniej jednak jest to świetny punkt wyjścia do dalszych prac. Serdecznie zachęcam do pozostawienia opinii, pytań oraz propozycji na kolejne wpisy w komentarzu.

Źródła i materiały dodatkowe

Dominik Szczepaniak

Zawodowo Senior Software Engineer w CKSource. Prywatnie bloger, fan włoskiej kuchni, miłośnik jazdy na rowerze i treningu siłowego.

Inne wpisy, które mogą Cię zainteresować

Zapisz się na mailing i odbierz e-booka

Odbierz darmowy egzemplarz e-booka 106 Pytań Rekrutacyjnych Junior JavaScript Developer i realnie zwiększ swoje szanse na rozmowie rekrutacyjnej! Będziesz też otrzymywać wartościowe treści i powiadomienia o nowych wpisach na skrzynkę e-mail.

Subscribe
Notify of
guest

1 Komentarz
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Dominik
Dominik
1 year ago

Fajne zdjęcie