Usando Seeders

03/11/2016 Seeders

Los Seeders

Y llegamos a una de los procesos que más me gustan, seedear la Base de Datos con datos de prueba para ayudarnos a comprobar qué tal vamos con el desarrollo de forma segura. Los Seeders son el mecanismo por el cual rellenamos nuestra BBDD local con datos aleatorios, con la finalidad de poder tener material con el que hacer pruebas sin miedo a romper nada importante.

Pra generar datos aleatorios usaremos Faker.js. Lo instalaremos con:

npm install -S faker

El desarrollo de esta funcionalidad lo dispondremos dentro del directorio database. En él crearemos un nuevo directorio llamado seeds. Dentro de éste, crearemos un nuevo archivo UsersSeeder.js con el siguiente contenido:

                
                    'use strict';
                    const crypto = require('crypto');
                    const faker = require('faker');
                    const mongoose = require('mongoose');
                    const Model = mongoose.model('User');
                    const DOCUMENTS = 10;

                    var getData = () => {
                        let data = [];
                        let salt = Model.getSalt();
                        let hash = Model.hashPassword('123456', salt); // All users with the same password

                        // Admin User
                        data.push({
                            email: "admin@admin.com",
                            name: "Admin",
                            role: 'admin',
                            password: hash,
                            passwordSalt: salt,
                            createdAt: new Date()
                        });

                        // Random Users
                        for (let i = 0; i < DOCUMENTS; i++) {
                            salt = Model.getSalt();
                            hash = Model.hashPassword('123456', salt);
                            data.push({
                                email: faker.internet.email(),
                                name: faker.name.firstName(),
                                role: 'user',
                                password: hash,
                                passwordSalt: salt,
                                createdAt: new Date()
                            });
                        }
                        return data;
                    };

                    var seed = (callback) => {
                        let data = getData();
                        Model.create(data, (err, result) => {
                            if (err) throw err;
                            console.log("Seeding " + Model.modelName + " collection");
                            callback();
                        });
                    };

                    module.exports = seed;
                
            

Lo único que exportamos en este fichero es la función seed() que será llamada desde el exterior cuando queramos seedear la colección de Usuarios.

Utilizamos el método create(data, callback) de Mongoose para crear todos los registros, donde data es un array con todos los Usuarios. Este array posee varios objetos. Cada objeto representa un Usuario. Los atributos name y email de estos Usuarios se obtienen usando Faker.js.

Los atributos password y passwordSalt se obtienen mediante los métodos getSalt() y hashPassword('123456', salt) de nuestro modelo User (definidos en el capítulo anterior, en server/models/User.js). Todos los usuarios tendrán el mismo password '123456' pero no compartirán el mismo hash, ya que el atributo salt es distinto en cada uno de ellos.

DatabaseSeeder

Ahora crearemos un archivo maestro que será el encargado de usar a todos los Seeds que creemos para llamar a sus respectivos métodos seed(). Dentro del directorio database, crearemos un archivo DataBaseSeeder.js, con el siguiente contenido:

                
                    'use strict';
                    require('dotenv').config();
                    require('../../server/models/User');
                    const db_host = process.env.DB_HOST;
                    const mongoose = require('mongoose');

                    var seeds = [
                        require('./UsersSeeder.js')
                    ];
                    var seedsDone = 0;

                    // Make the connection
                    mongoose.connect(db_host, (err, res) => {
                        if (err) throw 'ERROR: connecting to Database. ' + err;
                        console.log('Mongoose connected to ' + db_host);
                        mongoose.connection.db.dropDatabase();
                        seeds.forEach((seed) => {
                            seed(next);
                        });
                    });

                    var next = () => {
                        seedsDone++;
                        if (seedsDone === seeds.length) {
                            mongoose.connection.close(function () {
                                console.log(`Seeding Completed! (${seedsDone} seeds)`);
                            });
                        }
                    };
                
            

Y eso es todo! DataBaseSeeder realiza una conexión a la BBDD con Mongoose para seguidamente hacer un dropDatabase y empezar a llamar a todos los Seeders.

Cada uno de los Seeders deberán estar indicados en el array seed. Una vez se ha recorrido todo el array y se han ejecutado todos los seeds se procede a cerrar las conexión de Mongoose y a mostrar un mensaje en consola.

Para ejecutarlo, siempre y cuando tengamos una instancia de MongoDB en ejecución en nuestro sistema, sólo deberemos escribir:

node ./database/DataBaseSeeder

Con la Base de Datos populada, podremos acceder nuevamente a nuestra url /users y veremos que ahora tenemos unos usuarios!

Postman Users

También podemos hacer una búsqueda de un Usuario en concreto mediante el email, por ejemplo, /users/admin@admin.com nos devolverá únicamente al Usuario con dicho email. No es fascinante?

A user in Postman

En este último caso hemos usado la nueva ruta para realizar una búsque de un Usuario mediante su atributo email.

Seeders con Gulp

A que ya estábais echando de menos al tito Gulp? Pues ahora lo que haremos será crear una tarea para que, en lugar de escribir:

node ./database/DataBaseSeeder

Sólo tengamos que escribir:

gulp seed

Para ello, editaremos el gulpfile.js para añadir una nueva tarea:

                
                    ...
                    var exec = require('child_process').exec;
                    ...
                    /**
                     * This task will populate the database by calling and executing DataBaseSeeder.js file
                     */
                    gulp.task('seed', (cb) => {
                        exec('node ./database/seeds/DataBaseSeeder.js', function (err, stdout, stderr) {
                            console.log(stdout);
                            console.log(stderr);
                            cb(err);
                        })
                    });
                
            

Hemos necesitado usar el paquete child_process incluído en el core de Node. Este paquete nos permite ejecutar comandos de consola. De este modo, nuestra tarea seed hará una llamada a la ejecución del comando node ./database/seeds/DataBaseSeeder.js.

El código de todo el proyecto está aquí.

Si tienes alguna duda o sugerencia, no dudes en participar!