├── .gitignore ├── package.json ├── sandbox.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sequelize-reference", 3 | "version": "1.0.0", 4 | "description": "---", 5 | "main": "test.js", 6 | "scripts": { 7 | "test": "node sandbox" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/tmkelly28/sequelize-reference.git" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/tmkelly28/sequelize-reference/issues" 17 | }, 18 | "homepage": "https://github.com/tmkelly28/sequelize-reference#readme", 19 | "dependencies": { 20 | "pg": "^7.4.0", 21 | "pg-hstore": "^2.3.2", 22 | "sequelize": "^4.22.11" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sandbox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to the Sequelize sandbox! 3 | * Want to try out some sequelize code? 4 | * Define your models below, and then use them in the 5 | * promise chain! 6 | */ 7 | const Sequelize = require('sequelize') 8 | const db = new Sequelize('postgres://localhost:5432/pug-party') 9 | 10 | // write your models and associations here! 11 | 12 | db.sync({force: true}) 13 | .then(() => { 14 | // start using your models here! 15 | }) 16 | .then(() => { 17 | db.close() // closes the db gracefully 18 | }) 19 | .catch(err => { 20 | console.error('Uh oh, something does not compute!') 21 | console.error(err.message) 22 | console.error(err.stack) 23 | db.close() 24 | }) 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sequelize 2 | 3 | --- 4 | 5 | ## Connect to database 6 | 7 | ```javascript 8 | const Sequelize = require('sequelize') 9 | const db = new Sequelize('postgres://localhost:5432/your-db') 10 | ``` 11 | 12 | ## Defining Models 13 | 14 | ```javascript 15 | const Pug = db.define('pugs', { 16 | // column names go here 17 | }) 18 | ``` 19 | 20 | ### Column Types 21 | [Docs](http://docs.sequelizejs.com/manual/tutorial/models-definition.html#data-types) 22 | 23 | The example below demonstrates some common data types: 24 | 25 | ```javascript 26 | const Pug = db.define('pugs', { 27 | name: { 28 | type: Sequelize.STRING // for shorter strings (< 256 chars) 29 | }, 30 | bio: { 31 | name: Sequelize.TEXT // for longer strings 32 | }, 33 | age: { 34 | type: Sequelize.INTEGER 35 | }, 36 | birthday: { 37 | type: Sequelize.DATE 38 | }, 39 | colors: { 40 | type: Sequelize.ENUM('black', 'fawn') 41 | }, 42 | toys: { 43 | type: Sequelize.ARRAY(Sequelize.TEXT) // an array of text strings (Postgres only) 44 | }, 45 | adoptedStatus: { 46 | type: Sequelize.BOOLEAN 47 | } 48 | }) 49 | ``` 50 | 51 | #### Validators and Default Value 52 | [Docs](http://docs.sequelizejs.com/manual/tutorial/models-definition.html#validations) 53 | 54 | The example below demontrates usage for important validations (allowNull, min/max) and also demonstrates how to set a default value (defaultValue) 55 | 56 | ```javascript 57 | const Pug = db.define('pugs', { 58 | name: { 59 | type: Sequelize.STRING 60 | allowNull: false // name MUST have a value 61 | }, 62 | bio: { 63 | name: Sequelize.TEXT 64 | }, 65 | age: { 66 | type: Sequelize: INTEGER, 67 | validate: { 68 | min: 0, 69 | max: 100 70 | // note: many validations need to be defined in the "validate" object 71 | // allowNull is so common that it's the exception 72 | } 73 | }, 74 | birthday: { 75 | type: Sequelize.DATE, 76 | defaultValue: Date.now() 77 | // if no birthday is specified when we create the row, it defaults to right now! 78 | }, 79 | colors: { 80 | type: Sequelize.ENUM('black', 'fawn') 81 | }, 82 | toys: { 83 | type: Sequelize.ARRAY(Sequelize.TEXT) 84 | }, 85 | adoptedStatus: { 86 | type: Sequelize.BOOLEAN 87 | } 88 | }) 89 | ``` 90 | 91 | ### Instance Methods 92 | 93 | The code example below demonstrates an instance method. 94 | Instance methods are methods that are available on *instances* of the model. 95 | We often write these to get information or do something related *to that instance*. 96 | 97 | ##### Definition: 98 | ```javascript 99 | const Pug = db.define('pugs', {/* etc*/}) 100 | 101 | // instance methods are defined on the model's .prototype 102 | Pug.prototype.celebrateBirthday = function () { 103 | // 'this' in an instance method refers to the instance itself 104 | const birthday = new Date(this.birthday) 105 | const today = new Date() 106 | if (birthday.getMonth() === today.getMonth() && today.getDate() === birthday.getDate()) { 107 | console.log('Happy birthday!') 108 | } 109 | } 110 | ``` 111 | 112 | ##### Usage: 113 | 114 | ``` 115 | Pug.create({name: 'Cody'}) // let's say `birthday` defaults to today 116 | .then(createdPug => { 117 | // the instance method is invoked *on the instance* 118 | createdPug.celebrateBirthday() // Happy birthday! 119 | }) 120 | ``` 121 | 122 | 123 | ### Class Methods 124 | 125 | The code example below demonstrates a class method. 126 | Class methods are methods that are available on the *model itself* (aka the _class_). 127 | We often write these to get instances, or do something to more than one instance 128 | 129 | ##### Definition 130 | 131 | ```javascript 132 | const Pug = db.define('pugs', {/* etc*/}) 133 | 134 | // class methods are defined right on the model 135 | Pug.findPuppies = function () { 136 | // 'this' refers directly back to the model (the capital "P" Pug) 137 | return this.findAll({ // could also be Pug.findAll 138 | where: { 139 | age: {$lte: 1} // find all pugs where age is less than or equal to 1 140 | } 141 | }) 142 | } 143 | ``` 144 | 145 | ##### Usage 146 | ```javascript 147 | Pug.findPuppies() 148 | .then(foundPuppies => { 149 | console.log('Here are the pups: ', foundPuppies) 150 | }) 151 | .catch(err => { 152 | console.log('Oh noes!') 153 | // deal with errors 154 | }) 155 | ``` 156 | 157 | ### Getters and Setters 158 | [Docs](http://docs.sequelizejs.com/manual/tutorial/models-definition.html#getters-setters) 159 | 160 | Getters and setters are ways of customizing what happens when someone 'gets' or 'sets' a property on an instance. 'Get' and 'set' are referred to as "meta-operations" in JavaScript. 161 | 162 | ```javascript 163 | const someObj = {foo: 'bar'} 164 | someObj.foo // the 'get' meta-operation 165 | someObj.foo = 'baz' // the 'set' meta-operation 166 | ``` 167 | 168 | Normally, we expect that 'getting' a property will simply return the value at that key in the object, and 'setting' a property will set that property in the object. 169 | 170 | 'Getters' and 'setters' allow us to *override* that expected behavior. 171 | 172 | ##### Definition 173 | 174 | ```javascript 175 | const Pug = db.define('pugs', { 176 | name: { 177 | type: Sequelize.STRING, 178 | get () { // this defines the 'getter' 179 | // 'this' refers to the instance (same as an instance method) 180 | // in a 'getter', you should not refer to the names of the columns directly 181 | // as this will recursively call the getter and result in a stack overflow, 182 | // instead, use the `this.getDataValue` method 183 | return this.getDataValue('name') + ' the pug' 184 | // this getter will automatically append ' the pug' to any name 185 | }, 186 | set (valueToBeSet) { // defines the 'setter' 187 | // 'this' refers to the instance (same as above) 188 | // use `this.setDataValue` to actually set the value 189 | this.setDataValue('name', valueToBeSet.toUpperCase()) 190 | // this setter will automatically set the 'name' property to be uppercased 191 | } 192 | } 193 | }) 194 | ``` 195 | 196 | ##### Usage 197 | 198 | ```javascript 199 | // building or creating an instance will trigger the 'set' operation, causing the name to be capitalized 200 | Pug.create({name: 'cody'}) 201 | .then(createdPug => { 202 | // when we 'get' createdPug.name, we get the capitalized 'CODY' + ' the pug' from our getter 203 | console.log(createdPug.name) // CODY the pug 204 | 205 | // this is the 'set' operation, which will capitalize the name we set 206 | createdPug.name = 'murphy' 207 | console.log(createdPug.name) // MURPHY the pug 208 | }) 209 | ``` 210 | 211 | ### Virtual Columns 212 | 213 | "Virtual" columns are columns that *do not* get saved in your database - they are calculated on the fly based on the values of other columns. They are helpful for saving space if there are values we want to use on our instances that can be easily calculated. 214 | 215 | Virtual columns always have the data type of Sequelize.VIRTUAL. 216 | 217 | Virtual columns must have *at least* one custom 'getter' or 'setter' to be useful. This does not mean that getters and setters can _only_ be used with virtual columns though (see above). 218 | 219 | Virtual columns are similar to instance methods. The difference is you access virtual columns the same way you access a regular property (via the 'get' and 'set' meta-operation), whereas instance methods are functions that you must invoke. 220 | 221 | ##### Definition 222 | 223 | ```javascript 224 | const Pug = db.define('pugs', { 225 | firstName: { 226 | type: Sequelize.STRING, 227 | }, 228 | lastName: { 229 | type: Sequelize.STRING 230 | }, 231 | fullName: { 232 | type: Sequelize.VIRTUAL, 233 | get () { 234 | return this.getDataValue('firstName') + ' ' + this.getDataValue('lastName') 235 | } 236 | } 237 | }) 238 | ``` 239 | 240 | ##### Usage 241 | 242 | ```javascript 243 | Pug.create({firstName: 'Cody', lastName: 'McPug'}) 244 | .then(pug => { 245 | console.log(pug.fullName) // "Cody McPug" 246 | // however, if you look inside your database, there won't be a "fullName" column! 247 | }) 248 | ``` 249 | 250 | ### Hooks 251 | [Docs](http://docs.sequelizejs.com/manual/tutorial/hooks.html) 252 | 253 | When we perform various operations in sequelize (like updating, creating, or destroying an instance), that's not _all_ that happens. There are various stages that an instance goes through as it's being updated/created/destroyed. These are called *lifecycle events*. Hooks give us the ability to "hook" into these lifecycle events and execute arbitrary functions related to that instance. 254 | 255 | This can be useful in several ways. For example: 256 | 257 | * Before creating an instance of a User, we could hash that user's plaintext password, so that what gets saved is the hashed version 258 | * Before destroying an instance of a TodoList, we could also destroy all Todos that are associated with that TodoList. 259 | 260 | We define hooks on the model, but they are executed against instances when those instances pass through those lifecycle events. 261 | 262 | All hooks are defined using a function that takes two arguments. The first argument is the instance passing through the lifecycle hook. The second argument is an options object (rarely used - you can often ignore it or exclude it). 263 | 264 | Here's what the above two examples might look like. Note that there are several different ways that hooks can be defined (but they are mostly equivalent). 265 | 266 | ```javascript 267 | // given the following User model: 268 | const User = db.define('users', { 269 | name: Sequelize.STRING, 270 | password: Sequelize.STRING 271 | }) 272 | // we want to hook into the "beforeCreate" lifecycle event 273 | // this lifecycle event happens before an instance is created and saved to the database, 274 | // so we can use this to change something about the instance before it gets saved. 275 | 276 | User.beforeCreate((userInstance, optionsObject) => { 277 | userInstance.password = hash(userInstance.password) 278 | }) 279 | 280 | // This lifecycle hook would get called after calling something like: 281 | // User.create({name: 'Cody', password: '123'}) 282 | // and it would run before the new user is saved in the database. 283 | // If we were to inspect the newly created user, we would see that 284 | // the user.password wouldn't be '123', but it would be another string 285 | // representing the hashed '123' 286 | ``` 287 | 288 | ```javascript 289 | // given the following TodoList and Todo models: 290 | const TodoList = db.define('todolists', { 291 | name: Sequelize.STRING 292 | }) 293 | 294 | const Todo = db.define('todo', { 295 | name: Sequelize.STRING, 296 | completedStatus: Sequelize.BOOLEAN 297 | }) 298 | 299 | Todo.belongsTo(TodoList, {as: 'list'}) 300 | 301 | // we want to hook into the "beforeDestroy" lifecycle event 302 | // this lifecycle event happens before an instance is removed from the database, 303 | // so we can use this to "clean up" other rows that are also no longer needed 304 | TodoList.beforeDestroy((todoListInstance) => { 305 | // make sure to return any promises inside hooks! This way Sequelize will be sure to 306 | // wait for the promise to resolve before advancing to the next lifecycle stage! 307 | return Todo.destroy({ 308 | where: { 309 | listId: todoListInstance.id 310 | } 311 | }) 312 | }) 313 | ``` 314 | 315 | ### Associations 316 | [Docs](http://docs.sequelizejs.com/manual/tutorial/associations.html) 317 | 318 | Associations in Sequelize establish three things: 319 | 320 | 1. For one-one or one-many associations, it establishes a foreign key relationship between two tables (though a table could be related to itself). For many-many associations, it establishes a join-table that contains pairs of foreign keys. 321 | 2. It creates several special instance methods (like "getAssociation", "setAssociation", and potentially others depending on the type of association) that an instance can use to search for the instances that they are related to 322 | 3. It creates the ability to use "include" in queries to include data about related rows (known as "eager loading") 323 | 324 | ##### Types of Associations 325 | 326 | It is possible to specify the following associations in Sequelize: 327 | 328 | * `belongsTo` 329 | * `hasOne` 330 | * `hasMany` 331 | * `belongsToMany` 332 | 333 | These relations can be combined to establish *one-one*, *one-many* and *many-many* relationships, like so: 334 | 335 | * `one-one` 336 | * `A.belongsTo(B)` 337 | * `B.hasOne(A)` 338 | 339 | * `one-many` 340 | * `A.belongsTo(B)` 341 | * `B.hasMany(A)` 342 | 343 | * `many-many` 344 | * `A.belongsToMany(B, {through: 'AB'})` 345 | * `B.belongsToMany(A, {through: 'AB'})` 346 | 347 | ##### One-One Relations 348 | 349 | A one-one association is established by pairing a `belongsTo` and a `hasOne` association (though the `hasOne` is often omitted). 350 | 351 | Say we have two model tables, `Pug` and an `Owner`. We might associate them like so: 352 | 353 | ```javascript 354 | Pug.belongsTo(Owner) 355 | Owner.hasOne(Pug) 356 | ``` 357 | 358 | This means that a pug belongs to an owner, and an owner has one (and only one) pug. 359 | 360 | By doing this, the following three things will happen/be available to use: 361 | 362 | 1. The Pug table will have a foreign key column, "ownerId", corresponding to a primary key in the Owner table. 363 | 364 | *Pugs* - includes an ownerId! 365 | ``` 366 | id | name | createdAt | updatedAt | ownerId 367 | ``` 368 | 369 | *Owner* - no changes! 370 | ``` 371 | id | name | createdAt | updatedAt 372 | ``` 373 | 374 | 2. Sequelize automatically creates two instance methods for pugs, "getOwner" and "setOwner". This is because we defined `Pug.belongsTo(Owner)`. Likewise, owners get two instance methods, "getPug" and "setPug" (because we defined `Owner.hasOne(Pug)`). 375 | 376 | ```javascript 377 | pug.getOwner() // returns a promise for the pug's owner 378 | 379 | pug.setOwner(ownerInstanceOrID) // updates the pug's ownerId to be the id of the passed-in owner, and returns a promise for the updated pug 380 | 381 | owner.getPug() // returns a promise for the owner's pug 382 | 383 | owner.setPug(pugInstanceOrID) // updates the passed-in pug's ownerId to be the id of the owner, and returns a promise for the updated pug 384 | ``` 385 | 386 | 3. Sequelize will allow us to "include" the pug's owner, or the owner's pug in queries. 387 | 388 | ```javascript 389 | return Pug.findAll({ 390 | include: [{model: Owner}] 391 | }) 392 | .then(pugsWithTheirOwners => { 393 | console.log(pugsWithTheirOwners[0]) 394 | // looks like this: 395 | // { 396 | // id: 1, 397 | // name: 'Cody', 398 | // ownerId: 1, 399 | // owner: { 400 | // id: 1, 401 | // name: 'Tom' 402 | // } 403 | // } 404 | }) 405 | ``` 406 | 407 | Likewise (but note that if we do omit the `Owner.hasOne(Pug)`, this is not possible): 408 | 409 | ```javascript 410 | return Owner.findAll({ 411 | include: [{model: 'Pug'}] 412 | }) 413 | .then(ownersWithTheirPug => { 414 | console.log(ownersWithTheirPug[0]) 415 | // looks like this: 416 | // { 417 | // id: 1, 418 | // name: 'Tom', 419 | // pug: { 420 | // id: 1, 421 | // name: 'Cody', 422 | // ownerId: 1 423 | // } 424 | // } 425 | }) 426 | ``` 427 | 428 | ##### One-Many Associations 429 | 430 | A one-many association is established by pairing a `belongsTo` and a `hasMany` relation (though like `hasOne`, the `belongsTo` is sometimes omitted). 431 | 432 | Given our Pug and Owner, we might allow an owner to have multiple pugs like so: 433 | 434 | ```javascript 435 | Pug.belongsTo(Owner) 436 | Owner.hasMany(Pug) 437 | ``` 438 | 439 | This means that a pug belongs to an owner, and an owner can have many pugs (also known a a [grumble](https://www.google.com/search?q=grumble+of+pugs&ie=utf-8&oe=utf-8&client=firefox-b-1-ab)). 440 | 441 | By doing this, the following three things will happen/be available to use: 442 | 443 | 1. The Pug table will have a foreign key column, "ownerId", corresponding to a primary key in the Owner table. *Note: this is the same as a one-one association*. 444 | 445 | *Pugs* - includes an ownerId! 446 | ``` 447 | id | name | createdAt | updatedAt | ownerId 448 | ``` 449 | 450 | *Owner* - no changes! 451 | ``` 452 | id | name | createdAt | updatedAt 453 | ``` 454 | 455 | 2. Sequelize automatically creates three instance methods for pugs, "getOwner", "setOwner", and "createOwner". This is because we defined `Pug.belongsTo(Owner)`. Likewise, owners get a bunch of new instance methods, "getPugs", "setPugs", "createPug", "addPug", "addPugs", "removePug", "removePugs", "hasPug", "hasPugs", and "countPugs" (because we defined `Owner.hasMany(Pug)`). *Note: the difference here from one-one is that the owner's methods are now pluralized, and return promises for arrays of pugs instead of just a single pug!* 456 | 457 | ```javascript 458 | pug.getOwner() // returns a promise for the pug's owner 459 | 460 | pug.setOwner(owner) // updates the pug's ownerId to be the id of the passed-in owner, and returns a promise for the updated pug 461 | 462 | owner.getPugs() // returns a promise for an array of all of the owner's pugs (that is, all pugs with ownerId equal to the owner's id) 463 | 464 | owner.setPugs(arrayOfPugs) 465 | // updates each pug in the passed in array to have an ownerId equal to the owner's id. 466 | // returns a promise for the owner (NOT the pugs) 467 | ``` 468 | 469 | 3. Sequelize will allow us to "include" the pug's owner, or the owner's pugs in queries. 470 | 471 | ```javascript 472 | // this is the same as one-one 473 | return Pug.findAll({ 474 | include: [{model: Owner}] 475 | }) 476 | .then(pugsWithTheirOwners => { 477 | console.log(pugsWithTheirOwners[0]) 478 | // looks like this: 479 | // { 480 | // id: 1, 481 | // name: 'Cody', 482 | // ownerId: 1, 483 | // owner: { 484 | // id: 1, 485 | // name: 'Tom' 486 | // } 487 | // } 488 | }) 489 | ``` 490 | 491 | Likewise (but note that if we do omit the `Owner.hasMany(Pug)`, this is not possible): 492 | 493 | ```javascript 494 | // the difference is that instead of a "pug" field, the owner has a "pugs" field, which is an array of all that owner's pugs 495 | return Owner.findAll({ 496 | include: [{model: 'Pug'}] 497 | }) 498 | .then(ownersWithTheirPug => { 499 | console.log(ownersWithTheirPug[0]) 500 | // looks like this: 501 | // { 502 | // id: 1, 503 | // name: 'Tom', 504 | // pugs: [{ 505 | // id: 1, 506 | // name: 'Cody', 507 | // ownerId: 1 508 | // }] 509 | // } 510 | }) 511 | ``` 512 | 513 | ##### Many-Many Associations 514 | 515 | One-One and One-Many associations are very similar. Many-Many associations are different! Instead of placing a foreign key in one table, they create a brand new "join" table where each row contains a foreign key for each entity in the relationship. 516 | 517 | For our example, let's introduce a new table, Friend: 518 | 519 | ``` 520 | const Friend = db.define('friends', { 521 | name: Sequelize.STRING 522 | }) 523 | ``` 524 | 525 | A "friend" is a (human) person that is friends with pugs (but not necessarily a pug Owner themselves)! Any given "friend" may be a friend of many pugs. Likewise, any given pug will have many human friends! This is the nature of a many-to-many relationship. 526 | 527 | Here is how we define one: 528 | 529 | ``` 530 | Friend.belongsToMany(Pug, {through: 'friendship'}) 531 | Pug.belongsToMany(Friend, {through: 'friendship'}) 532 | ``` 533 | 534 | The "through" parameter defines the name of the join table that gets created. 535 | 536 | By establishing the relation above, the following *four* things happen: 537 | 538 | 1. A brand new table called `"friendship"` is created. 539 | 540 | *friendship* 541 | ``` 542 | createdAt | updatedAt | pugId | friendId 543 | ``` 544 | 545 | No changes occur to the `pug` or `friend` tables! 546 | 547 | 2. A new Sequelize model becomes automatically generated for the table: 548 | 549 | ```javascript 550 | const Friendship = db.model('friendship') 551 | ``` 552 | 553 | You can use this model the same way you use any other Sequelize model (you can query it, create instances, etc). 554 | 555 | 3. Sequelize automatically creates several instance methods for pugs and for friends, the same ones as created by `hasMany` above: 556 | 557 | ``` 558 | pug.getFriends() // returns a promise for the array of friends for that pug 559 | pug.addFriend(friend) // creates a new row in the friendship table for the pug and the friend, returns a promise for the friendship (NOT the pug OR the friend - the "friendship") 560 | pug.addFriends(friendsArray) // creates a new row in the friendship table for each friend, returns a promise for the friendship 561 | pug.removeFriend(friend) // removes the row from the friendship table for that pug-friend, returns a promise for the number of affected rows (as if you'd want to destroy any friendships...right?) 562 | pug.removeFriends(friendsArray) // removes the rows from the friendship table for those pug-friend pairs, returns a promise for the number affected rows 563 | 564 | // analogous to above ^ 565 | friend.getPugs() 566 | friend.addPug(pug) 567 | friend.addPugs(pugsArray) 568 | friend.setPugs(pugsArray) 569 | friend.removePug(pug) 570 | friend.removePugs(pugsArray) 571 | ``` 572 | 573 | 4. Allows us to include a pug's friends, or a friend's pugs 574 | 575 | ```javascript 576 | Pug.findAll({ 577 | include: [{model: Friend}] 578 | }) 579 | .then(pugsWithFriends => { 580 | console.log(pugsWithFriends[0]) 581 | // looks like this: 582 | // { 583 | // id: 1, 584 | // name: 'Cody', 585 | // friends: [ 586 | // { 587 | // id: 1, 588 | // name: 'CodyFan <3' 589 | // }, 590 | // ....any many more! 591 | // ] 592 | // } 593 | }) 594 | ``` 595 | 596 | The inverse also applies if we `Friend.findAll({include: [{model: Pug}]})` 597 | 598 | --- 599 | 600 | ## Querying Using Models 601 | 602 | ### Model.findOne 603 | [Docs](http://docs.sequelizejs.com/manual/tutorial/models-usage.html#-find-search-for-one-specific-element-in-the-database) 604 | 605 | Finds a single instance that matches the search criteria (even if there are more than one that match the search criteria - it will return the first it finds) 606 | 607 | ```javascript 608 | Pug.findOne({ 609 | where: {name: 'Cody'} 610 | }) 611 | .then(foundPug => { 612 | console.log(foundPug) 613 | }) 614 | ``` 615 | 616 | ### Model.findById 617 | [Docs](http://docs.sequelizejs.com/manual/tutorial/models-usage.html#-find-search-for-one-specific-element-in-the-database) 618 | 619 | Finds the instance with the specified id. 620 | 621 | ```javascript 622 | Pug.findById(1) 623 | .then(pugWithIdOne => { 624 | console.log(pugWithIdOne) 625 | }) 626 | ``` 627 | ### Model.findAll 628 | [Docs](http://docs.sequelizejs.com/manual/tutorial/models-usage.html#-findall-search-for-multiple-elements-in-the-database) 629 | 630 | Finds all instances that match the search criteria. If no criteria are given, it returns all the instances in the table. 631 | 632 | ```javascript 633 | Pug.findAll() // will find ALL the pugs! 634 | .then(allPugs => { 635 | console.log(allPugs) 636 | }) 637 | ``` 638 | 639 | #### "Select" Clauses ("attributes") 640 | [Docs](http://docs.sequelizejs.com/manual/tutorial/querying.html#attributes) 641 | 642 | You can select specific columns to be included in the returned instance by specifying an "attributes" array. 643 | 644 | ```javascript 645 | Pug.findAll({ 646 | attributes: ['id', 'name', 'age'] // like saying: SELECT id, name, age from pugs; 647 | }) 648 | .then(allPugs => { 649 | console.log(allPugs) // [{id: 1, name: 'Cody', age: 7}, {id: 2, name: "Murphy", age: 4}] 650 | // note that all the pugs only have key-value pairs for id, name and age included 651 | }) 652 | ``` 653 | 654 | #### "Where" Clauses 655 | [Docs](http://docs.sequelizejs.com/manual/tutorial/querying.html#where) 656 | 657 | You can narrow down the search in a `findAll` by specifying a `where` clause 658 | 659 | ```javascript 660 | Pug.findAll({ 661 | where: { // like saying: SELECT * from pugs WHERE age = 7; 662 | age: 7, 663 | } 664 | }) 665 | .then(sevenYearOldPugs => { 666 | console.log(sevenYearOldPugs) 667 | }) 668 | ``` 669 | 670 | Specifying multiple options uses "AND" logic 671 | 672 | ```javascript 673 | Pug.findAll({ 674 | where: { // like saying: SELECT * from pugs WHERE age = 7 AND color = 'black'; 675 | age: 7, 676 | color: 'black' 677 | } 678 | }) 679 | .then(sevenYearOldBlackPugs => { 680 | console.log(sevenYearOldBlackPugs) 681 | }) 682 | ``` 683 | 684 | ##### Search Operators 685 | [Docs](http://docs.sequelizejs.com/manual/tutorial/querying.html#operators) 686 | 687 | We often want to specify comparisons like "greater than", "less than" in our `where` clauses. 688 | 689 | In sequelize, we need to use special properties called "operators" to do this. Here are some of the most common. (Note: there are of course many more operators - there's no need to memorize all of them, but be sure to read through them so that you have an idea of what you can do!) 690 | 691 | *Note*: Up until very recently, we used regular object properties to refer to operators. In upcoming versions of Sequelize, these will be replaced by Symbols that must be obtained from Sequelize, like so: 692 | 693 | ```javascript 694 | // Sequelize stores these operators on the `Sequelize.Op` module: 695 | const Op = Sequelize.Op 696 | 697 | Pug.findAll({ 698 | where: { 699 | age: { 700 | [Op.lte]: 7 // square brackets are needed for property names that aren't plain strings 701 | } 702 | } 703 | }) 704 | ``` 705 | 706 | The examples below demonstrate using operators as regular object properties, with the Symbol equivalent in an adjacent comment. 707 | 708 | Here is a list of some of the more commonly used operators, and their usage: 709 | 710 | * $gt: Greater than // soon to be replaced by [Op.gt] 711 | * $gte: Greater than or equal // soon to be replaced by [Op.gte] 712 | * $lt: Less than // soon to be replaced by [Op.lt] 713 | * $lte: Less than or equal // soon to be replaced by [Op.lte] 714 | * $ne: Not equal // soon to be replaced by [Op.ne] 715 | * $eq: Equal // soon to be replaced by [Op.eq] 716 | * $or: Use or logic for multiple properties // soon to be replaced by [Op.or] 717 | 718 | 719 | ```javascript 720 | // gt, gte, lt, lte 721 | 722 | // SELECT * FROM pugs WHERE age <= 7 723 | Pug.findAll({ 724 | where: { 725 | age: { 726 | $lte: 7 // soon to be replaced by [Op.lte] 727 | } 728 | } 729 | }) 730 | ``` 731 | 732 | ```javascript 733 | // $ne 734 | 735 | // SELECT * FROM pugs WHERE age != 7 736 | Pug.findAll({ 737 | where: { 738 | age: { 739 | $ne: 7 // soon to be replaced by [Op.ne] 740 | } 741 | } 742 | }) 743 | ``` 744 | 745 | ```javascript 746 | // $or 747 | 748 | // SELECT * FROM pugs WHERE age = 7 OR age = 6 749 | Pug.findAll({ 750 | where: { 751 | age: { 752 | $or: [ // soon to be replaced by [Op.or] 753 | {$eq: 7}, // soon to be replaced by [Op.eq] 754 | {$eq: 6} // soon to be replaced by [Op.eq] 755 | ] 756 | } 757 | } 758 | }) 759 | ``` 760 | 761 | #### Joins/Includes (aka "Eager Loading") 762 | [Docs](http://docs.sequelizejs.com/manual/tutorial/models-usage.html#eager-loading) 763 | 764 | If we have two tables that are associated with each other, we often want to join that data together. In raw SQL queries, our favorite tool for this is an INNER JOIN. We can do something similar in Sequelize - it just goes by the slightly different name of "eager loading". Don't get hung up on the terminology - when you see "eager loading", think "join two tables". 765 | 766 | If two tables have an association, we can "include" information from the associated table like so: 767 | 768 | ``` 769 | const Pug = db.define('pugs', {name: Sequelize.STRING}) 770 | const Owner = db.define('owners', {name: Sequelize.STRING}) 771 | 772 | Pug.belongsTo(Owner) 773 | 774 | Pug.findAll({ // we want to find all the pugs, and include their owners 775 | include: [{model: Owner}] 776 | }) 777 | .then(pugs => console.log(pugs)) 778 | // [{name: 'Cody', ownerId: 1, owner: {name: 'Tom'}}, ...etc] 779 | ``` 780 | 781 | *Important!* A Model can only eagerly load an association if the association is defined *on* that model. 782 | 783 | This means that for the above example, if we attempt to do the following: 784 | 785 | ``` 786 | const Pug = db.define('pugs', {name: Sequelize.STRING}) 787 | const Owner = db.define('owners', {name: Sequelize.STRING}) 788 | 789 | // the relation only exists on Pug 790 | Pug.belongsTo(Owner) 791 | 792 | Owner.findAll({include: [{model: Pug}]}) // this will error! 793 | ``` 794 | 795 | ...it will error! For us to include Pug when we query Owner, we must also establish the 'hasOne' or 'hasMany' association between Owners and Pugs. 796 | 797 | Example with `hasOne`: 798 | 799 | ```javascript 800 | const Pug = db.define('pugs', {name: Sequelize.STRING}) 801 | const Owner = db.define('owners', {name: Sequelize.STRING}) 802 | 803 | Pug.belongsTo(Owner) 804 | Owner.hasOne(Pug) // 1-1 association 805 | 806 | Owner.findAll({include: [{model: Pug}]}) 807 | .then(owners => console.log(owners)) // [{name: 'Tom', pug: {name: 'Cody', ownerId: 1}}] 808 | ``` 809 | 810 | Example with `hasMany`: 811 | 812 | ```javascript 813 | const Pug = db.define('pugs', {name: Sequelize.STRING}) 814 | const Owner = db.define('owners', {name: Sequelize.STRING}) 815 | 816 | Pug.belongsTo(Owner) 817 | Owner.hasMany(Pug) // 1-Many Relationship 818 | 819 | Owner.findAll({include: [{model: Pug}]}) 820 | .then(owners => console.log(owners)) // [{name: 'Tom', pugs: [{name: 'Cody', ownerId: 1}]}] 821 | ``` 822 | 823 | Note that the difference between the two examples above is that in the `hasOne` case, the resultant owenrs have a "pug" field with the name of their (single) pug. In the `hasMany` case, the resultant owners have a "pugs" (plural!) field with an _array_ of their (possibly many) pugs! 824 | 825 | This same rule applies to many-to-many associations! 826 | 827 | ### Model.findOrCreate 828 | [Docs](http://docs.sequelizejs.com/manual/tutorial/models-usage.html#-findorcreate-search-for-a-specific-element-or-create-it-if-not-available) 829 | 830 | Finds an instance that matches the specified query. If no such instance exists, it will create one. This method is a little funny - it returns a promise for an array! The first element of the array is the instance. The second element is a boolean (true or false), which will be true if the instance was newly created, and false if it wasn't (that is, an existing match was found). 831 | 832 | In the example below, assume we do not have any existing row in our pugs table with the name 'Cody'. 833 | 834 | ```javascript 835 | Pug.findOrCreate({where: {name: 'Cody'}}) 836 | .then(arr => { // findOrCreate is a promise for an array! 837 | const instance = arr[0] // the first element is the instance 838 | const wasCreated = arr[1] // the second element tells us if the instance was newly created 839 | console.log(instance) // {id: 1, name: 'Cody', etc...} 840 | console.log(wasCreated) // true 841 | 842 | return Pug.findOrCreate({where: {name: 'Cody'}}) // now if we findOrCreate a second time... 843 | }) 844 | .then(arr => { 845 | const instance = arr[0] 846 | const wasCreated = arr[1] 847 | console.log(instance) // {id: 1, name: 'Cody', etc...} 848 | console.log(wasCreated) // false -> the query found an existing pug that matched the query 849 | }) 850 | ``` 851 | 852 | It's often preferably to handle with a promise for an array using `.spread`. We can do this because the promises returned by Sequelize are "Bluebird" promises. 853 | 854 | ```javascript 855 | Pug.findOrCreate({where: {name: 'Cody'}}) 856 | .spread((instance, wasCreated) => {/* ...etc */}) 857 | ``` 858 | 859 | With pure JavaScript, we can use array destructuring to do the same thing: 860 | 861 | ```javascript 862 | Pug.findOrCreate({where: {name: 'Cody'}}) 863 | .then(([instance, wasCreated]) => {/* ...etc */}) 864 | ``` 865 | For other examples of this pattern: http://es6-features.org/#ParameterContextMatching 866 | 867 | ### Model.build 868 | 869 | Creates a temporary instance. Returns the instance. This instance is NOT yet saved to the database! 870 | 871 | ```javascript 872 | const cody = Pug.build({name: 'Cody'}) 873 | console.log(cody) // we can start using cody right away...but cody is NOT in our db yet 874 | ``` 875 | 876 | ### Model.create 877 | 878 | Creates and saves a new row to the database. Returns a promise for the created instance. 879 | 880 | ```javascript 881 | Pug.create({name: 'Cody'}) 882 | .then(cody => { 883 | // now, cody is saved in our database 884 | console.log(cody) 885 | }) 886 | ``` 887 | 888 | ### Model.update 889 | 890 | Updates all instances that match a query. 891 | Takes two parameters: the first parameter contains the info you want to update. The second parameter contains the query for which instances to update. 892 | 893 | Like `findOrCreate`, it returns a promise for an array. The first element of the array is the number of rows that were affected. The second element of the array is the affected rows themselves. 894 | 895 | ```javascript 896 | // update all pugs whose age is 7 to have an adoptedStatus of true 897 | Pug.update({ 898 | adoptedStatus: true 899 | }, { 900 | where: {age: 7}, 901 | returning: true, // needed for affectedRows to be populated 902 | plain: true // makes sure that the returned instances are just plain objects 903 | }) 904 | .spread((numberOfAffectedRows, affectedRows) => { // because we return a promise for an array, .spread is recommended 905 | console.log(numberOfAffectedRows) // say we had 3 pugs with the age of 7. This will then be 3 906 | console.log(affectedRows) // this will be an array of the three affected pugs 907 | }) 908 | ``` 909 | 910 | ### Model.destroy 911 | 912 | Destroys all instances that match a query. 913 | It returns a promise for the number of rows that were deleted. 914 | 915 | ```javascript 916 | Pug.destroy({ 917 | where: { 918 | age: 7 // deletes all pugs whose age is 7 919 | } 920 | }) 921 | .then(numAffectedRows => { 922 | console.log(numAffectedRows) // if we had 3 pugs with the age of 7, this will be 3 923 | }) 924 | ``` 925 | 926 | --- 927 | 928 | ## Using Instances 929 | 930 | ### instance.save and instance.update 931 | [Docs](http://docs.sequelizejs.com/manual/tutorial/instances.html#updating-saving-persisting-an-instance) 932 | 933 | If we already have an instance, we can save changes with either instance.save or instance.update 934 | 935 | Both returns promises for the saved/updated instance 936 | 937 | Here's an example using save: 938 | ```javascript 939 | // we already have a pug instance, which we've put in a variable called cody 940 | console.log(cody.age) // 7 941 | cody.age = 8 // we can change the age to 8 (but it isn't saved in the database yet) 942 | cody.save() // we can use .save to actually save to the database 943 | .then(updatedCody => { 944 | console.log(updatedCody.age) // 8 945 | }) 946 | ``` 947 | 948 | Here's another example using update: 949 | ```javascript 950 | console.log(cody.age) // 7 951 | cody.update({age: 8}) 952 | .then(updatedCody => { 953 | console.log(updatedCody.age) // 8 954 | }) 955 | ``` 956 | 957 | ### instance.destroy 958 | [Docs](http://docs.sequelizejs.com/manual/tutorial/instances.html#destroying-deleting-persistent-instances) 959 | 960 | If we want to remove an individual instance from the database, we can use instance.destroy. 961 | It returns a promise that will be resolved when the row is removed from the database. 962 | (The promise itself does not resolve to anything in particular though - it's always just an empty array) 963 | 964 | ```javascript 965 | cody.destroy() // no! bye Cody! 966 | .then(() => { // no need to expect the promise to resolve to any useful value 967 | // now the cody row is no longer in the database 968 | }) 969 | ``` 970 | 971 | --------------------------------------------------------------------------------