Loopback: Creating a Seed Script
Populating your database automatically
Now that we have our API setup we need data to persist. Adding data to our tables manually is not efficient, and we need a way of quickly populating data for not only prototyping but also testing. Creating a Seed Script will solve this problem, by clearing and creating table data in less than 2s.
This article builds on two other articles that I have recently written about Loopback.js. The Github is linked at the bottom along with the other articles. This series is loosely coupled, so hopefully, you can jump right in. To the left is the current working API data model.
Setup
To get started creating out seed script the first thing we need to do is create two files in the ./server/scripts
folder. These files can be called anything for the purpose of this article, mine will be called dummy-data.js
and seed.js
Creating Data File
Before we seed data, we must have data to seed. This is where the dummy-data.js
file comes in. Going through all models, create arrays of objects under the name of the model they correspond to. The name field of a model can be found in the .json
file for that model.
For our example below module.exports.student
matches "name":"student"
These arrays will be iterated in our script and each object will be used to create a row in our database.
For relational data, you need to manually add the foreign ids. Mysql ids increment from 0, which makes it predictable. This is critical in seeding valid relations.
I like to override the implicitly generate model properties for relations. This allows me to match up the property names I create with the foreign keys I enter.
For our example, the foreign key studentId in dummy-data.js must match the foreign key property name in your model(ie studentId).
Creating Seed Script
In the seeding process, there are two main steps: deleting existing data and creating new data. To do both of these operations I use the destroyAll
and create
methods that can be found on the model objects. Detail for those methods can be found here.
Imports
Just noting here that you must import the server and grab the data source and models off of it.
Also, I am just using Chalk to make my command line more colorful. That is completely optional.
Deleting
For deleting data from our database I wrap the destroyAll
method to provide some feedback on the console.
Essentially, all we are doing here is getting the model by name, running destroyAll
on it, and calling the callback.
Creating
Similarly to deleting data, I just wrap the create
method and provide feedback to the console.
Bringing it all together
Because there are constraints on our relationships we need to create the models in order of increasing relationships and delete them in order of decreasing relationships. Otherwise, we will run into conflicts where we are creating data with a relationship that can’t exist, or we are deleting data that is referenced elsewhere.
In our example, this means creating (Students and Subjects) then (Lockers and Class) then (Enrollment and Teacher) and deleting in reverse order.
All of the create and destroy methods are async and instead of returning promises they currently take a callback function. I believe the loopback team is currently working to upgrade this. Until they finish this change and to avoid callback hell, I use the Async library. The Async library has a method called eachSeries. This method takes in a list of items, a function to call, and a callback to run when all of the elements are finished.
I call eachSeries twice. Once to loop through the model names and delete and then again to loop through the model names in reverse and create.
Create Node scripts
To ease in the refreshing of the data I like to create two scripts in the package.json.
Thus when you want to update your schema all you have to do is call npm run migrate
and npm run seed
Conclusion
Now we have a fully working seed command. You can see example output below.
Paired with the migration command I have previously discussed, these two commands can make testing and prototyping with your API drastically more efficient.
Now to find out which dependency is using timers.enroll()
🤟Josh
Previous articles in this series.