How To Create Factory Relationships from a Pool of Data
In this lesson, we'll learn how we can refactor our fake data seeder to allow us to assign cast members and crew members to our movies via our many-to-many relationships from a single pool of cineast records.
- Author
- Tom Gobich
- Published
- Apr 05
- Duration
- 13m 55s
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
How To Create Factory Relationships from a Pool of Data
-
[MUSIC]
-
So let's say that instead of creating a brand new Cineast for these,
-
we instead want to use the pool of Cineast that we have and
-
assign them for the relationship from that pool.
-
Essentially reusing Cineast as we go about movies so
-
that we have multiple Cineast assigned as cast members or
-
crew members to multiple movies rather than just one by one as we have here.
-
Let's hide PGM back away and let's remove what we have so far.
-
Getting this back to how it was prior to last lesson.
-
Okay, let's put a couple line breaks here so
-
that we can focus on just this one line for right now.
-
Let's plop the results of this factory's creation into a variable.
-
So let's do const.
-
And since this is the only movie factory that we're not doing anything to,
-
we're not applying any states, not tapping through it or anything like that.
-
Let's put these in a variable just called our default movies,
-
since it's using all the defaults.
-
This should be an array of movie models as you can see here.
-
What we can do is actually just use these models now as actual relationships
-
to create relations randomly for
-
the Cineast pool that we're providing into our create movies method.
-
Okay, so we're going to get a pool of promises.
-
So let's give ourselves a place to house those.
-
So up here at the top of our create movies method, let's just do const
-
promises equals an array and we can specify the type for this as a promise any array.
-
Okay, we don't really care what the promise is going to return at the end of
-
the day, we just want to make sure that we can wait for
-
all of them to finish before we return out of this method.
-
Okay, so let's loop over our default movies like so, and
-
we'll have an individual movie here.
-
We'll do const crew Cineast equals.
-
And let's create ourselves a utility to grab a random number of Cineast out of
-
our Cineast array.
-
So let's create a private method called get random that accepts in an array.
-
We'll need a type for this array so
-
that we can return back the same type that we provide in.
-
For that, we'll need to add in a type variable to our method itself, and
-
we'll call that T.
-
Then we'll provide the number to plug out of the array so
-
that we can get any random number that we want.
-
First, let's shuffle our array.
-
So we'll shuffle equals array.sort 0.5 minus math random.
-
Then with our shuffled array, we'll go ahead and return shuffle.slice,
-
start at the zero index, and go to the pluck number that we've provided it.
-
So now if we scroll up from our Cineast array,
-
we should be able to do this.get random, provide in our Cineast array, and
-
say that maybe we want to pluck five out of that array.
-
If we take a look at our crew Cineast type, we now have a Cineast array.
-
Awesome.
-
Well, in terms of creating our relationship,
-
what we really care about are just the IDs.
-
So let's do crew Cineast IDs there, map over our results,
-
pluck out the ID, and return that ID.
-
So now our crew Cineast IDs should be a number array, which it is.
-
We can go ahead and give this a copy and
-
do the exact same thing for our cast Cineasts as well.
-
For this, so that we can discern them, let's do three.
-
Okay, with the individual movie that we're looping over,
-
we can now grab the relationship, so related crew members dot, and
-
attach in the random array of IDs that we've grabbed.
-
So that would be our crew Cineast IDs like so.
-
And that's how we can create records using a many to many relationship.
-
From the movie model instance, we grab the relation we want to create records for,
-
and attach IDs for that relation.
-
And it will populate our many to many pivot table with the movie's ID,
-
as well as each one of the relation IDs that we provide it.
-
In our particular case though, we have pivot data we also need to provide.
-
And this does complicate the call a little bit.
-
But if we take a look at a hard coded version,
-
we'll see that it's still relatively straightforward.
-
So instead of providing an array of IDs, we'll now want to provide in
-
an object where the key is the ID.
-
So if we want to bind a Cineast with an ID of one to the movie that we're working
-
with, the key would be the ID of one for that Cineast.
-
And then the value for this key is going to be the pivot table data that should be
-
created for this Cineast with an ID of one, and they're binding to this movie.
-
So that would be their title of, let's say, camera operator,
-
as well as their sort order of zero.
-
And then we just do that same thing over and over again for
-
each one of the Cineasts that we want to bind.
-
Ignore my poor formatting there, but say if we want to then attach a Cineast with
-
an ID of two, we do that exact same thing with a key of now two.
-
And that will bind both a Cineast with an ID of one with this particular pivot table
-
information, and a Cineast with an ID of two with this pivot table information.
-
So we could change that up to make them unique per each one, and
-
it would account for that accordingly.
-
So what we would want to do is do that in a loop based fashion for
-
our loop of IDs here.
-
So we'll scroll down, get rid of the object that we have here so far.
-
And the easiest way to do that would be to reduce through the array.
-
So we'll do crew Cineast IDs, reduce.
-
We'll have our overall object that will create the relationships,
-
as well as the current ID that we're working on.
-
And then we're also going to want the index so that we can increment our sort.
-
Okay, we'll return that back and instantiate the default value as an object.
-
So for our object, we'll bind in the current ID we're working with and
-
have that value equal our intermediary table data.
-
So we could have a title of say camera operator and
-
our sort order of the current index.
-
Then we will return back our new object, give that a save for our formatting.
-
And we do have a couple red squigglies going on still.
-
So first we have already used the variable index,
-
that is if we scroll up right there.
-
So we'll just call this i.
-
I think we're all relatively familiar with i at this point.
-
So we'll move forward with that.
-
And then second, we're getting an implicit any type here.
-
So all that we need to do to fix that is provide a type to our reduce method.
-
So we'll do two angle brackets there.
-
And let's hover over attached and
-
that will provide us the type that we're working with right here.
-
So let's give that a copy and paste it in.
-
Now we don't have a model object imported.
-
So let's just type model object, hit tab to auto import that and
-
we should be good, awesome.
-
So now we're looping over each one of our crew Cineast IDs,
-
adding in an object where the key is the individual ID and
-
the object is the pivot table data that we want created with that ID.
-
And then returning back that new object,
-
which will then be attached into our movie via our crew members relationship.
-
We'll want to do this several times over for
-
each one of the movies that we're creating.
-
So let's extract this out into a helper method as well.
-
So we'll give this a copy, scroll down, and let's do private attach crew members.
-
We'll paste that in.
-
And what we want to do is provide in a movie of type movie,
-
provide in our IDs array, which will be a number array.
-
And then for our titles, we'll create an array and
-
pluck a random title out of that array for the Cineast that we're binding.
-
And we just need to update our crew Cineast IDs to just IDs now,
-
give it a save to fix that formatting.
-
And we can go ahead and just return that back and this will be an async method.
-
Let's also have this method randomly pluck the IDs for
-
us as well to just get rid of one extra duplicate line.
-
So attach random crew members and instead of IDs,
-
let's have this be our actual Cineast array, just like so.
-
Okay, let's scroll up to where we are grabbing random crew Cineast IDs.
-
Give that a copy, scroll back down and paste it within our attach random crew
-
members array.
-
I misspelled Cineast, so we'll give that a copy and
-
paste it there as well to get that correct.
-
Okay, and then we can provide the number that we want to create into this argument
-
as well, so we'll just have an argument called number, which will be a type number.
-
And provide that into our get random method, so number there.
-
And let's update the name of this to be just IDs.
-
Awesome, so now our attach random crew members method takes in a movie,
-
takes in an array of Cineasts and a number to randomly pluck from the Cineasts.
-
It will get that random number and their IDs from our Cineast array,
-
attach them to our movie via our relationship.
-
And now all that's left to do is make our Cineast title random as well.
-
So let's go ahead and scroll up to the top of our cedar here.
-
And let's do titles as a string array equals an array.
-
And we'll do camera operator as one, maybe an art director,
-
hair and makeup production manager.
-
Might have somebody for wardrobe, a line producer, sound mixer,
-
maybe a cinematographer.
-
I think I spelled that wrong.
-
Okay, I think that's supposed to be an A and a gaffer.
-
And that should be good for our titles.
-
So we'll scroll back down to where we are attaching our random crew members.
-
And for the title, instead of placing in a hard coded string,
-
we will do this get random, provide in our this title.
-
Let's pluralize that name.
-
Scroll back up, plop an S on the end of that.
-
There we go, scroll back down, titles.
-
And we just want one, so we'll provide one there.
-
And then we need the first result, so we'll do zero there.
-
Okay, so now we have our attach random crew members.
-
Let's do the exact same thing for our cast members as well.
-
So we'll give that whole method there a copy and a paste and attach random cast members.
-
The relationship for this will now be cast members.
-
And instead of providing titles, we'll instead want to provide in character names.
-
So instead of creating a manual list of character names,
-
we can actually make use of our Sinisfactory to get a character name randomly.
-
So inside of our reduce call here, let's do const record equals await Sinisfactory.makeStubbed.
-
And this will make us a Cineast using our Sinisfactory,
-
but it won't actually persist it to the database.
-
Now we just have a Cineast record that doesn't exist in the database available to us.
-
And we can do record.fullname to provide the random full name
-
that we got from our Sinisfactory into our character name.
-
However, this is asynchronous.
-
So let's move this outside of this call to simplify things.
-
And let's create many instead.
-
The number that we want to create is the total number of cast members that we're trying to create here.
-
So we'll just pass our number directly in there.
-
This is now records.
-
And now we can do records, reach for the index.fullname instead, and everything will be happy.
-
All right, so now it's time to make use of these two attach calls.
-
So scroll back up, get rid of everything that we have here, just like so.
-
And we can even get rid of these two lines here.
-
Now let's change our game plan here a little bit.
-
So instead of plopping all of our movies into a variable, looping over them individually,
-
let's plop all of our movies into a single variable.
-
So up here at the top, and we'll do let movie records set the type to a movie model array
-
and instantiate the value to an empty array.
-
We'll scroll back down, and we'll just concatenate in each of the results as we create them.
-
So we'll do movie records.concat, wrap that up there.
-
Movie records equals the resulting concatenation.
-
And we'll want to do that for each one of these three here as well.
-
So movie records equals movie records.concat, and wrap those up as well, just like so.
-
And then let's scroll up and do the exact same thing for the ones that we're tapping
-
over as well.
-
So let's do let movie records equals those there, and then we can just get rid of our
-
instantiation up there.
-
Let's get rid of our promises as well, since we have these all housed inside of a single
-
array.
-
We can just do const promises equals movie records.map.
-
We have our individual movie, and then inside of here, we'll await this, attach random cast
-
members, provide in our movie, provide in the pool of Cineasts we have in our array,
-
and then the number that we want to create.
-
Let's do four for right now.
-
Okay.
-
And then we can return this.attach crew members, movie, our cynist pool, and let's create three
-
cast members.
-
All right.
-
Lastly, these two things aren't happy because that's missing parentheses, and then we need
-
to make it async as well.
-
All right.
-
So let's await promise.all our array of promises.
-
Okay.
-
So now we have our array of movie models, which contains the result of each one of the
-
movie factories that we run, including the ones that we tap over as well.
-
We are then awaiting the results of the attach random cast members and attach random crew
-
members for each one of those movies right here.
-
So if we did everything correctly, we should be able to jump back into our terminal.
-
Let's clear that out and let's rerun our migration refresh seed, just like so.
-
Okay.
-
Everything completed successfully.
-
So it appears like everything would be correct.
-
Let's jump into PgAdmin.
-
Let's scroll up.
-
Let's right click on our database, refresh, scroll back down.
-
If we right click now on our crew movies table, view edit data, let's do all rows.
-
Okay.
-
Look at that.
-
We got 1260 rows back.
-
However, the pool that we worked with was just a pool of 10 Cineasts.
-
So as we look through our cynist ID column here, we should not see any above 10 since
-
these are the first records that we're creating.
-
It should be one through 10 for the cynist IDs.
-
So as we scroll through this, it looks like everything went correctly.
-
I'm not seeing anything above 10.
-
Awesome.
-
We have our sort order going one through two as well.
-
And this is our crew movies table.
-
So if we jump back into our text editor, we are creating three crew members.
-
So our sort there seems accurate as well.
-
Let's run through our cast movies next and verify that.
-
So we'll right click, view edit data, all rows.
-
All right.
-
We got 1680.
-
Same thing here.
-
We should not see any above 10 and we're creating four here.
-
So we should see sorts zero through three.
-
So scroll through here.
-
Everything here looks a-okay as well.
-
Awesome.
-
So now we have a pool of Cineasts that we're creating right here.
-
If we wanted more variants, we can create more Cineasts.
-
So we could create a hundred there and now we wouldn't have so much repetition within
-
our crew movies.
-
So let's go ahead and rerun our seed with that.
-
So let's clear out, rerun that, and then we'll have a pool of 100 Cineasts that we're working
-
through.
-
There we go.
-
So things should be a little bit more dynamic there.
-
And the Cineasts are randomly being bound as crew and cast members to the movies that
-
that we're creating.
-
Introduction
-
Fundamentals
-
2.0Routes and How To Create Them5m 23s
-
2.1Rendering a View for a Route6m 29s
-
2.2Linking Between Routes7m 51s
-
2.3Loading A Movie Using Route Parameters9m 17s
-
2.4Validating Route Parameters6m 6s
-
2.5Vite and Our Assets6m 38s
-
2.6Setting Up Tailwind CSS9m 5s
-
2.7Reading and Supporting Markdown Content4m 32s
-
2.8Listing Movies from their Markdown Files8m 51s
-
2.9Extracting Reusable Code with Services7m 4s
-
2.10Cleaning Up Routes with Controllers4m 52s
-
2.11Defining A Structure for our Movie using Models9m 38s
-
2.12Singleton Services and the Idea of Caching6m 11s
-
2.13Environment Variables and their Validation4m 16s
-
2.14Improved Caching with Redis10m 44s
-
2.15Deleting Items and Flushing our Redis Cache6m 46s
-
2.16Quick Start Apps with Custom Starter Kits6m 28s
-
2.17Easy Imports with NodeJS Subpath Imports8m 40s
-
-
Building Views with EdgeJS
-
3.0EdgeJS Templating Basics8m 49s
-
3.1HTML Attribute and Class Utilities6m 9s
-
3.2Making A Reusable Movie Card Component10m 24s
-
3.3Component Tags, State, and Props4m 53s
-
3.4Use Slots To Make A Button Component6m 56s
-
3.5Extracting A Layout Component5m 13s
-
3.6State vs Share Data Flow2m 59s
-
3.7Share vs Global Data Flow6m 7s
-
3.8Form Basics and CSRF Protection6m 13s
-
3.9HTTP Method Spoofing HTML Forms3m 3s
-
3.10Easy SVG Icons with Edge Iconify7m 57s
-
-
Database and Lucid ORM Basics
-
4.0Configuring Lucid and our Database Connection4m 3s
-
4.1Understanding our Database Schema9m 35s
-
4.2Introducing and Defining Database Migrations18m 35s
-
4.3The Flow of Migrations8m 28s
-
4.4Introducing Lucid Models5m 43s
-
4.5Defining Our Models6m 49s
-
4.6The Basics of CRUD11m 56s
-
4.7Defining Required Data with Seeders11m 11s
-
4.8Stubbing Fake Data with Model Factories13m 48s
-
4.9Querying Our Movies with the Query Builder15m 30s
-
4.10Unmapped and Computed Model Properties3m 24s
-
4.11Altering Tables with Migrations7m 6s
-
4.12Adding A Profile Model, Migration, Factory, and Controller2m 57s
-
4.13SQL Parameters and Injection Protection9m 19s
-
4.14Reusable Query Statements with Model Query Scopes8m 11s
-
4.15Tapping into Model Factory States9m 15s
-
4.16Querying Recently Released and Coming Soon Movies4m 59s
-
4.17Generating A Unique Movie Slug With Model Hooks7m 59s
-
-
Lucid ORM Relationships
-
5.0Defining One to One Relationships Within Lucid Models5m 49s
-
5.1Model Factory Relationships2m 54s
-
5.2Querying Relationships and Eager Vs Lazy Loading5m 17s
-
5.3Cascading and Deleting Model Relationships5m 16s
-
5.4Defining One to Many Relationships with Lucid Models6m 56s
-
5.5Seeding Movies with One to Many Model Factory Relationships5m 24s
-
5.6Listing A Director's Movies with Relationship Existence Queries8m 41s
-
5.7Listing and Counting a Writer's Movies8m 41s
-
5.8Using Eager and Lazy Loading to Load A Movie's Writer and Director5m 18s
-
5.9Defining Many-To-Many Relationships and Pivot Columns9m 48s
-
5.10Many-To-Many Model Factory Relationships4m 50s
-
5.11A Deep Dive Into Relationship CRUD with Models18m 5s
-
5.12How To Create Factory Relationships from a Pool of Data13m 55s
-
5.13How To Query, Sort, and Filter by Pivot Table Data9m 47s
-
-
Working With Forms
-
6.0Accepting Form Data12m 15s
-
6.1Validating Form Data with VineJS9m 29s
-
6.2Displaying Validation Errors and Validating from our Request7m 16s
-
6.3Reusing Old Form Values After A Validation Error2m 3s
-
6.4Creating An EdgeJS Form Input Component5m 28s
-
6.5Creating A Login Form and Validator5m 1s
-
6.6How To Create A Custom VineJS Validation Rule9m 7s
-
-
Authentication & Middleware
-
7.0The Flow of Middleware7m 49s
-
7.1Authenticating A Newly Registered User4m 14s
-
7.2Checking For and Populating an Authenticated User2m 10s
-
7.3Logging Out An Authenticated User2m 24s
-
7.4Logging In An Existing User6m 54s
-
7.5Remembering A User's Authenticated Session6m 55s
-
7.6Protecting Routes with Auth, Guest, and Admin Middleware5m 36s
-
-
Filtering and Paginating Queries
-
8.0Creating A Movie List Page3m 43s
-
8.1Filtering A Query By Pattern Likeness7m 9s
-
8.2Filtering Our List by Movie Status5m 47s
-
8.3How To Apply A Dynamic Sort Filter To Your Query7m 12s
-
8.4Joining SQL Tables To Order By A Related Column4m 49s
-
Validating Query String Filter Values7m 23s
-
How To Paginate Filtered Query Results9m 15s
-
Pagination First, Last, Next, and Previous Buttons4m 2s
-
-
User Watchlist
-
An Alternative Approach to Many-To-Many Relationships4m 56s
-
Toggling A Movie in an Authenticated User's Watchlist9m 56s
-
Listing and Filtering User Watchlist Items7m 34s
-
Allowing Users To Toggle A Movie As Watched4m 44s
-
Filtering By User's Watched Status6m 7s
-
Defining A Composite Unique Constraint4m 46s
-
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!