TypeORM Tutorial: Migrations, queries, and more! | NestJS

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
especially if you want to use a typo rm in production this is the video that you definitely should not miss all right hey guys i've been making a lot of sgs content lately and i've been getting some pretty good feedback in the comments i very much appreciate those comments something that i always use in a lot of those next gs tutorials is typo rm which i never really went into a deeper detail deep dive um explaining how to use it and how to use it with different databases and stuff like that so i figured i'd make this specific video to cover just type orm and how to work with it and add in some details that i didn't cover before especially if you want to use a typo rm in production um this is the video that you definitely should not miss so we're gonna split up this video into five uh core parts part one is gonna be set up and installation how do you connect your database part two uh we're gonna talk about uh creating your entities your tables how do you write migrations which you absolutely should know if you're gonna do production work and then we're gonna talk about utilizing dependency injection to inject our entities into our services which then allows us to do the actual querying which goes into our part four which is the repository api which uh that's where i'm gonna cover things like how do you query your tables how do you insert how do you update how do you delete you know basically your crud your typical crud operations um those are good fundamentals to have i'll also cover how to create custom queries and then finally we'll talk about in part 5 relations you know if you have obviously in a relational database you're going to have relationships between your tables so how do you go and uh get those relationships how do you do joins and stuff like that so we'll cover that in the last part all right so let's jump right into part one you know set up installation you can see that there's an npm install script here that we're going to copy so i've got a basic skeleton application here where i use the nscli to generate this so it's just got a basic module and a controller and a service i'm going to go ahead and paste that install script you'll notice that i didn't copy the my sql 2 dependency i'm going to use sqlite here and with typeorm it has really good support for pretty much all of the main relational databases that you can think of like postgres mysql i personally use sqlite for these tutorials just because it's so easy to set up you know i just install it via npm i don't have anything else to to configure but you absolutely can use this with your own uh relational database of choice all right so once you've got typeorm installed in the root app module you'll then want to add typeorm module dot for root and this expects that you're passing in an object that will be forwarded down to your database driver so for example if let's say we were using mysql right you'll see that in their their example over here they're using mysql 2 as their database driver if you go into the documentation for mysql 2 you'll notice that for for you to create a connection you're passing an object like this which has at minimum host user database you know it might also have password and stuff like that so that's the object that it requires for that driver so that's the object that you would pass into this for root method similarly maybe if you're using postgres you know you might use the the pg package as your driver and that's going to have its own requirements for what should be defined inside this object now what i'm actually going to do here is i'm going to create a new file in the root called orm config.ts and i'm going to create the config here and this is specifically because later we're going to use the type ram cli so i want i want this config to be accessible on that as well so we're going to import config from oram config and then we're gonna pass that in here and then we'll do our uh database connection definition over here so i mentioned earlier that this object really could be almost anything depending on your database driver one nice tip that i can add here is you can actually specify a specific type for that connection object so for example if we did have a mysql database you can do something like mysql connection options and it's going to give you the shape of that object which has you know type mysql or mariadb and then you'll also notice that if we go into the interface that it's extending right it's asking for those things that we talked about earlier like url host username password now in our case we're not using mysql where i said we're using sqlite so we can do sqlite connection options and you can also take a look at the the shape of that it just requires a type of sqlite and a database string as your primary required property so we're going to do type sqlite and then database and i'm just going to put db over here so this string here is going to be the the name of the file so sqlite kind of saves your database into a file so it's going to be named just db and you'll see that in a little bit here and then the main thing that we need for typo rm specifically is an entities array this src and then anything in that it has entity in its file name we're going to assume is an entity so think about it as we're we're following a convention and we're using that convention to identify which of our files represents our database schema and i'll show an example of that in a little bit here so another option you can add here is synchronize which you see is it indicates if the database schema should all should be auto created on every application launch um it also says be careful about using this in production and really you shouldn't you shouldn't use this in production because what this will do is it will look for your entity files and it's if it sees that your schema has a mismatch with what's in the database it's automatically gonna synchronize your your database to what your schema is so that could mean if um you deleted an entity it will drop a table so you got to be careful about making sure you don't have this to true in production so this is really only uh should be utilized for local development you know if you're just doing a quick poc and actually let's go ahead and do a quick example for you to so you can see this in action all right so in our src folder we're going to create a new user.ntt.ts file again following that convention of having dot entity in the file name if it's an entity so we're gonna do export class user [Music] and we're gonna decorate this with entity so what does that mean it we're basically telling type program that this class represents the shape of our user table in the database so for example maybe you have an id in that database and it's auto incrementing integer so there is also a decorator for that of primary generated column so we can do id number and then maybe we have a second column for a name which is just a string oops and you just have to add column here and that's going to turn into a varchar column in the database so now we have this basic entity in our database configuration we're saying that it's going to look for entities in the dist so what that means is we need to have a build so if we run build when we run build we're going to have a new dist folder here and it's going to have src and it should have an user entity that javascript there so that's going to be found by this glob pattern so let's go ahead and run our application which part of the thing that does is it makes a a dist a build for us on the fly and then what you should notice is that it creates a the first time you run this it's going to create that db file over here in a root right because that's the name that we provided here now let's go ahead and use i have dbver here db the dbeaver however you want to say that and you can use this to or your own whatever database client you like to use to connect to your databases um let's go ahead and create a new sqlite connection which is in this db file i'm just going to open that and when we go in we can see the tables and there's the new user table there which has columns id and name right so let's go ahead and let's try to simulate the synchronize happening here if i were to for example add a new column here of something let's see it's just another string the next time that my application reruns if we go in here and do a refresh [Music] now there's a new something column right so that's what what that's what i mean by synchronize is to automatically gonna make your database match with your um schema that's represented by your entities again that's very good for local development very bad for production all right so let's talk about how do we fix this for for production right we don't want synchronize to be turned on so we'll do false in production what you should instead be using is you should be using migrations and migrations are basically you can kind of think of it as your you're creating sql scripts that represent the changes that you want to run into your database so how we're going to accomplish migrations is actually through uh typewrim itself it has support for for migrations so to accomplish it first you need to install uh typorm globally so that you have access to the cli so npm install dash g type 4m and then you're also going to want to global install ts node that's going to allow you to run the cli against typescript files and then it also tells us that we should add this type or m script into our package.json so i'm going to do that next now once we have that the next thing you're going to want to do is back into our connection options we're going to do a migrations property here which you provide an array and this is going to say it's going to tell type 4 and where do i look for migrations again we're going to do this src and then we're going to say that you should look in db migrations and take any file in there that any file that's in there now that tells type or where are the migrations located we also have to tell the cli itself where to put the migrations so we're gonna do migrations directory src db migrations right so we're trying to get it into this folder right here so let's give this a a shot again remember that synchronize should be false at this point so what i'm first gonna do is i'm actually gonna delete this old tv that i have in here and then i'm gonna start dev again to recreate it so that we we start with a fresh sqlite database okay so you'll see the db got added again now i'm going to close this we're starting from a fresh database let's go ahead and write our first migration so one of the cool things with typo rm is it can auto-generate the migrations for you again this is why it's looking for um the entities it can look into the entities that you have and then looks into your database and then it kind of does like a diff it tries to figure out what's the difference and then it's going to automate auto create a migration for you so let's go ahead and see that in action so in the package.json i'm going to create a new command here i'm going to call it type or m or sorry i'm going to call it migration colon generate and we said that in our configuration we want the uh we want it to look in our dist again so that means that you probably should run a build first and run build and then from here we're gonna do npm run type orm migration generate and then dash dash dash n so it's really just this type run type rn piece is running this script and then uh we're doing a dash n here because we're gonna need to pass in a name uh so i know that's probably really confusing but once you kind of see it running it makes a lot more sense so and actually i misspelled migration here so let me fix that now once you have that you can go into your terminal and just do npm run migration generate and then we can pass in a name of you know maybe we do user migration because we created a user entity recently and you can see that it does the build and then eventually it's going to run this part of it and notice that it's passing the user migration string here into our dash n flag here so what did that do if we look into the src folder we now have a db folder in there that also has a migrations folder and then it created this file right so it auto generated for us a script that tells the database hey create table user with these columns basically matching your entity and you also notice that there is an up and there's a down the down is always the inverse of whatever you're doing in the up all right so now that we have this migration let's go ahead and figure out how to run this so back into our package.json i'm going to create another script in here for migration run and similar thing we want to run the build first npm run build and then after building we're going to do npm run type rm migration run all right and let's go ahead and give that a shot i'm just going to run it in this utility here all right it's an run migration run same thing it's going to do a build it's going to find our migration and then it's going to pass it down to type our migration run it's going to run it and you can see it in the the terminal here it's doing a bunch of stuff right it's starting a transaction to create our user table and if you go back into our db beaver right remember i i deleted the the user table uh previously so it's not there and when i refresh this because our migration ran we now have a new again it's back the user table and then if we actually select our migrations table which it also creates it has it kind of uses that as a way to track which of your which of your migration scripts are you already ran and which ones didn't so if it notices that the next time you run migration run and there's a new migration and it hasn't been added to this table yet then it knows that oh now i need to run that migration to synchronize our our database so again every time you wanna kind of update your database all you need to do is you know update your entity files create any new ones that you want and then you run that generate script and then it's automatically going to create the mic the migration files for you and then you just trigger a run and it's up to you when you trigger that run so for example maybe in production you wanna as part of your continuous integration or continuous deployment you might wanna run your migrations prior to deployment alright so hopefully that made sense uh let me know in the comments if that was confusing i can be confusing for people that are new to it you also can create your own custom migrations if you want so maybe you want to insert data as an example which is not going to be represented by your entities right like if you want to seed your database tables you can create a manual migration where you know you just write your own sql basically just make sure to add that to the migrations folder and actually there's also a you can also do type or migration colon create and that's going to create a new file for you that just has the up and down methods all right so for the rest of this tutorial i'm actually going to turn this back to true just because it keeps things simpler so that i don't have to keep writing migrations and writing migrations throughout this tutorial it'll just make it uh it'll just make it so that our changes automatically get reflected into the database and that's what i want for a demo like this all right so that concludes the first two parts of this video you know we covered how to connect to the database and then how to create your entities and effectively represent your schema for your database and then how to get your database to match that schema right you either synchronize or you do migrations all right next what we want to do is how do we then utilize these entities to um create queries against them so for example maybe we want to query all of our users all right so first thing that you want to do is within the module you're working with in this case we just have this one root module you ideally should be creating a a new module for each domain so in in typical development i likely should have created a user module right and then that entity would live inside it but we're just going to stick with this root app module for simplicity but you know uh just go with me here imagine that this is a user module what you're gonna do is you're gonna add typewriter module for feature and then this takes an array of entities so we're going to add user and what that's going to enable us to do is within our services or providers we can then add to a constructor and you can do something like inject repository and then we're gonna do private users repository which just has a type of repository of entity user and then i actually forgot that you also have to pass the uh the entity itself in here which we also forgot to import right so we're importing our user.entity we're passing it in here we're creating a new variable in this class a member in this class called user repository it has this type syntax is a little bit verbose but it's not too bad so as an example let's start talking about the repository api so let's do the basics first uh perhaps you want to do a get all right you want to do get all users which returns a promise of collection of users how do you do that you do this dot user repository and let me actually make that plural users alright usersrepository.find so that find is effectively equal to select star users select star from user right if you know your your sql and make sure to return right so there you go how about how do you find a specific user maybe you want to do get one by id which uh we said that our ids are integers so maybe we do something like this returns a promise of a user right and you can do this.usersrepository.find1 and you can pass in the id directly like that you can also do find one or fail which i personally like because if you just do find one that would be equivalent to again select star from user where [Music] user.id equals the id that you passed in right which i select if you if it didn't find anything it's just going to return nothing which is probably not the behavior that you want in a typical application if you couldn't find something you probably want to communicate that to the user in some way so you can do find one or fail which what this will do is it's going to throw an error which you can then wrap this if you want in a try catch right like this right so if we were to put this in here if you were to await be sure to add your async right if it doesn't find it it's going to throw an error and then you can handle that in here if you want or you can throw the arrow back right um so that's how i like to do finding by one i always almost almost always use or fail because i want to communicate when i can't find that thing all right next let's talk about how do you insert how do you add to our table to our user table you can do let's do a create user method here which uh probably takes in the fields that you want but let's say for now we just want to take in the name which is a string and we want this to return the newly created user so this is also going to be a promise of a user in our user entity we said that it has a name property i'm going to delete this for simplicity so it's just going to have an id and a name so to do that to create a new one we're just going to do new user equals this dot usersrepository.create and then you pass in the the fields that you want to specify so in our case it's name and what create is it's effectively equivalent to something like constant new user equals new user right and then you know it does new user dot name equals the name that we passed right so it's kind of a shorthand for instantiating that class now once you have that creation that doesn't mean that it's saved in your database you still have to do this.userrepository.save and then you pass in your newly created entity that's the so if you look at the documentation for save it says that it saves a given entity in a database if it does not exist it's going to do an insert otherwise it's gonna do an update so that means you can also use this for updating the user right so this is gonna do insert in our specific case here because we're passing in a new that doesn't have an id so that's going to do a database insert since we sort of covered it let's do update you know maybe we want to allow for name changing so let's do update user um you know let's do name again here and again we probably want to return the updated user right like if you have a client you almost want to get the new data back now kind of similar thing we saw that the save can do an update for us so we're going to copy that but we're going to do for us to be able to do this we first need to find that user right in a database which we already do we are we've already handled in our code over here so you can just do const user equals await let's add our async this dot get one by id and then you pass in uh the id which we actually are missing in our parameters here right or you can also use this directly if you want it's it's basically the same thing um but if you're doing error handling like this you know it might be good to reuse so this gets back our entity it queries it for us and then we can do our manipulations our updates so in this case we're saying that we want to we want to allow the application to change the user's name so we're going to do user.name equals the name that passed in and then we're going to save it so the save is going to trigger a database update and it should update that row and maybe i'll demo this a little bit later but i want to type out a lot of this stuff first all right so you can probably kind of see where i'm going with this i'm i'm effectively covering how to do crud right so this is your um your reading this is your create this is your update and then we just need to do a a delete so we can do delete user same thing we want to know who to delete and then in this case we probably want to return the deleted user so you can kind of do a similar thing here where you query the user first and then similarly this should be async because we're awaiting and then you can do await this.usersrepository.remove and we pass in our entity and then we're just going to return it again because we want to communicate to our client the object that we just removed or i think you can actually just return this directly because it looks like remove returns that same user entity so we can delete this all right so that's basically your crud right there um if you're looking at the type rm documentation you likely will also notice that there's there's also in an insert method so like this but the reason we don't use insert is because that what this returns is a promise of the insert result not the actual entity itself it'll just say that oh it inserted [Music] one row or something like that but it doesn't return actual user that got inserted save on the other hand does return the the user that got saved they knew that row that got updated or created so in in a crud scenario where you're creating and almost always you usually want to get back the thing that you just created the create and save combo is almost always the one you want there kind of similar thing for what we're doing with the the update and deletes here like i think there's a delete um method where you can just pass in the the id right so you can pass in the id but same thing if you do it that way you get back the delete result you don't get back the deleted entity and there's a lot of scenarios where you want to get back that that entity that you deleted updated or created because you want to inform the client or the user the user interface um on what data is updated right so i personally will use remove there but could be your own you know your own preference it's also good to know that using the repository you can also create your own custom queries so for example you know you can do something like user repository dot create query builder and you can pass in an alias here so in our case let's name this user and you can do all sorts of things with this like for example maybe you just want to select the name uh maybe you want to do a left join or maybe you want to do a aware right so this is a good if you know sql well and you have a very custom query and you just want to represent the the sql that you know into the javascript api um this is a good this is a good approach right so it has a lot of those things that you would uh probably care about like order by right group by kind of those core sql uh statements and there's really good documentation for that in the type or um you know query builder documentation right it's got all of this stuff right so take a look at this documentation if you want to learn more i can't really cover this because there's so much it basically covers like almost everything that you can do with sql so you can kind of just think if you have very custom queries that's not something you can do with the repository api query builder is your best friend there alright so let's maybe go ahead and test the stuff that we have so far we have a basic app controller here let's go ahead and oh we already have our app service imported there let's maybe change this to uh do something different so right now if i run this when i run this and go to localhost it's gonna give me that hello world message and that's because of the the get hello that we have here let's go ahead and just change that to maybe you know maybe we're going to create a new user and we're just going to return that so as an example let's do return this dot app service dot create user and let's just pass in a name here of um let's just do my name and then this is complaining to me because i did not import the user right so when i call that again i expect that it's gonna add me to the database so let me hit refresh here right and then it returned us a that new entity that got created and you can go back into your database viewer if you want if we query our user table now you should see that same brow all right so we know that our you know our user is getting created you know maybe let's do another one and then see if we can do an update right so we're gonna create a new user with name test and then we're gonna do this at app service dot uh update user which requires an id so we actually want to do something like this and we're going to immediately update that name to something else why don't we go ahead and just return this so what i expect to happen when i refresh the page again is it's going to create a new user with name test and then immediately it's going to update it to something else so i'm gonna hit refresh and we got back a new row and his name is now something else it ran very quickly but if you slow it down you know you add some um some timers in there if you want you will notice that it first does create with tests and then ultimately updates so if we query the user table again now we got those two and then you know just to make sure everything is working why don't we go ahead and do our delete um let's just do delete user and then i'm just going to delete the first one which is the one that has my name on it again if i go back to my browser and refresh it returns me that new deleted entity and if we go to our database and we do a requery here now we just have that second row the first one got deleted right so all of our stuff is is working you can also do i don't think i did the get all and now this is going to return a collection of users and i expect that when i refresh i am going to get back an array of users right so all of our crowd stuff is working obviously i did not create this in in proper you know uh you i really should have created a user module with its own user controller and its own user service but where in this tutorial were specifically uh learning the type orm repository api and stuff like that um make sure to check out my other videos where i do kind of show you how to do this properly with you know the domains for user and having its own module and such alright so finally i think the last part that i said i'll cover is relations so obviously with relational tables right relational databases you you have tables that likely have relationships between them so for example maybe a user has a pet so let's go ahead and create a new um pet entity it's going to do pet entity dot ts and kind of similar thing we're going to do export class pet wrap this in an entity we'll just copy the same fields that the user has let's say that this bet has id and name and make sure to import any missing imports and in the typo rm documentation it goes into a lot of stuff in more details regarding relations uh you know so you can if you know your your sql relationships well you know that you can do stuff like one to one many to one one to many many too many and depending on which one you choose it's gonna type where i'm just gonna figure out for you how to represent that in the database so for example if you do a many-to-many it's going to create a new intermediary table for you that represents the the relationship between your two entities if you do something like a many to one which we'll go ahead and do that actually [Music] or a one too many it's it's gonna add a new id property in that table that represents the relationship so let's go take a look at what that looks like so for example we know that a pet has an owner of type user and we can say that we have a many to one relationship here and you have to provide the type which is user and then you have to provide in that entity what's the matching property in this case it would be user dot pets and we got a red squiggly here because that doesn't exist yet if we go into the other side you can say that the user has pets of type pet right and you can do your um one to many over here which is the inverse relationship which has a type of pet and we're gonna do within those path we do owner all right so all of our squigglies should be gone so now that you have that relationship uh one of the things you can do if we go back to our um our service here in our user repository within the find it has a special property that you can pass in here called relations and you can pass in an array of relations in this case we maybe want to pull pets right we have this new property and what what this is going to do is it's going to do the select start from user and then it's also going to do the join to get the rest of the paths right join with paths so to do a quick example here let me run the application back in our controller since we're already doing get all let's take a look at what that returns at the moment so it's going to return the person with the something else name and it just has an empty array of paths so just for the sake of time i'm going to go ahead and manually add a new pad in here obviously you can go through the same exercise we just did with creating a a service for like a pet service that is able to create pets and stuff but i'm going to cheat and i'm going to add a new pet in here instead so i'm going to do a new insert into pet here with name buddy and i'll use an id of one there if we do a select of our pet table now we got our pet there actually this owner id should be two because we we deleted owner one right so in our user table we have uh just that person with id2 so we're saying that this pet his owner is this guy with the name something else so now if we go back into our application if i refresh here there you go now we have we're able to query the user as well as his or her pets and all of that all we had to do was add this array so it's super that's something that's super convenient with with type or m is that it's able to pull in relations for you like that all right so that's really it that's the basics of it you know you obviously can change this as needed like for example maybe if a pet can belong to multiple users right like if it has a mom and a dad um this probably should be a many-to-many relationship and then you can also specify in here stuff like what happens on delete right like if you want to do like on delete cascade and stuff like that you can do that in the configuration of this uh decorator here alright guys so that's it for this video leave a thumbs up if you found it useful drop a comment if there's anything that you feel i should have covered or if there's other content that you want me to cover in the future i would love to know of of whatever you think uh anyways thanks and i'll see you on the next video [Music] you
Info
Channel: Marius Espejo
Views: 102,261
Rating: undefined out of 5
Keywords: typescript, typeorm, javascript, nestjs tutorial, nestjs graphql, nestjs microservices, nestjs authentication, nestjs, typeorm postgres, typeorm mysql, typeorm sqlite, postgresql tutorial for beginners, postgres, mysql, sqlite, node, node js tutorial, expressjs mysql, mean stack tutorial, mern stack, database, relational databases, nestjs database, nestjs database connection, nestjs typeorm, typeorm nestjs tutorial, typeorm tutorial, typescript tutorial, typescript for beginners
Id: sNosL578ECo
Channel Id: undefined
Length: 45min 38sec (2738 seconds)
Published: Sun Mar 14 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.