Search code examples
mysqlnode.jsinner-joinsequelize.js

Unable to join 2 tables with a foreign key using sequelize


I have two tables I created using sequelize. Please see the models below. I have a client side post requests that sends data from client to both tables. but when I post, then everything is getting stored except foreign key is null in the profession Table so I can't join them together

User model

module.exports = function(sequelize, DataTypes){
        var User = sequelize.define('User', {
            first_name: {
                type: DataTypes.STRING,
                allowNull: false,
                validate: {
                  len: [1, 160]
                }
              },
              last_name: {
                type: DataTypes.STRING,
                allowNull: false,
                validate: {
                  len: [1, 160]
                }
              },
              email: { 
                type: DataTypes.STRING,
                allowNull: false,
                validate: {
                  len: [1,100],
                  isEmail: true
                }
              },
              password: {
                type: DataTypes.STRING,
                allowNull: false,
                validate: {
                    len: [1,20]
                }
              },
              gender: {
                type: DataTypes.STRING,
            },
            pet:{
                type: DataTypes.STRING,
                allowNull: true,
                validate:{
                    len:[1, 100]
                }
            }

    });
    // Association between user and professions, where one user can be linked to many professions.
    User.associate = function(models) {
      User.hasMany(models.Profession, {
        onDelete: "cascade",
        foreignKey : "UserId"
      });
    };
    return User;
    };

Profession Model

module.exports = function(sequelize, DataTypes) {
    // Creates a table "profession" in our network database
      var Profession = sequelize.define("Profession", {
        // LIST OF COLUMNS //

        //Category is a string type, cannot be null, and validates for length
        category: {
          type: DataTypes.STRING,
          allowNull: false,
          validate: {
            len: [1, 160]
          }
        }
    });
   // Adds a foreign key to the user id from the "user" table to be associated with corresponding profession
   Profession.associate = function (models) {
    Profession.belongsTo(models.User, {
      // foreignKey: {
      //   allowNull: false
      // }
      foreignKey: "UserId"
    });
  };

    return Profession;
  };

Additionally, The following is the error I'm getting when running the server

Unhandled rejection Error: Can't set headers after they are sent.
    at validateHeader (_http_outgoing.js:489:11)
    at ServerResponse.setHeader (_http_outgoing.js:496:3)
    at ServerResponse.header (/Users/Veena/Desktop/Project2/tests/modalnavigation_test/node_modules/express/lib/response.js:767:10)
    at ServerResponse.send (/Users/Veena/Desktop/Project2/tests/modalnavigation_test/node_modules/express/lib/response.js:170:12)
    at ServerResponse.json (/Users/Veena/Desktop/Project2/tests/modalnavigation_test/node_modules/express/lib/response.js:267:15)
    at /Users/Veena/Desktop/Project2/tests/modalnavigation_test/routes/api-routes.js:54:11
    at tryCatcher (/Users/Veena/Desktop/Project2/tests/modalnavigation_test/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/Users/Veena/Desktop/Project2/tests/modalnavigation_test/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/Users/Veena/Desktop/Project2/tests/modalnavigation_test/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromise0 (/Users/Veena/Desktop/Project2/tests/modalnavigation_test/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/Users/Veena/Desktop/Project2/tests/modalnavigation_test/node_modules/bluebird/js/release/promise.js:693:18)
    at Async._drainQueue (/Users/Veena/Desktop/Project2/tests/modalnavigation_test/node_modules/bluebird/js/release/async.js:133:16)
    at Async._drainQueues (/Users/Veena/Desktop/Project2/tests/modalnavigation_test/node_modules/bluebird/js/release/async.js:143:10)
    at Immediate.Async.drainQueues (/Users/Veena/Desktop/Project2/tests/modalnavigation_test/node_modules/bluebird/js/release/async.js:17:14)
    at runCallback (timers.js:785:20)
    at tryOnImmediate (timers.js:747:5)
    at processImmediate [as _immediateCallback] (timers.js:718:5)

Client Side jQuery to send post request

// submit button is triggered
$('#submitbutton').click(function(event){
    event.preventDefault();
    console.log('submit button is triggered');
    formSubmit();
})

    function formSubmit() {       
             var submitThisData = {
            // Grabbing the values of user data in an object called userData
            userData :{
                first_name: $('#firstname').val().trim(),
                last_name: $('#lastname').val().trim(),
                email: $('#email').val().trim(),
                password: $('#Password').val().trim(),
                gender: $('#gender').val().trim(),
                pet: $('#pet').val().trim(),
            },
            // Grabbing the values of profession data that will go into profession table in an object called userData
            professionData : {
                // UserId: 1,
                category: $("#category").val().trim()
        } 
        }


        // Ajax post request for creating a member in our database. 

        $.post("/api/members", submitThisData).then(function(result){
            alert('user stored');
            console.log(result);
        })


         }
      });

Routing

// Dependencies
// =============================================================

// Requiring our User model
var db = require("../models");

// Routes
// =============================================================
module.exports = function(app) {


    // POST route for saving a User
  app.post("/api/members", function(req, res) {
    console.log(req.body);    

    db.User.create({
      first_name: req.body['userData[first_name]'],
      last_name: req.body['userData[last_name]'],
      email: req.body['userData[email]'],
      password: req.body['userData[password]'],
      gender: req.body['userData[gender]'],
      pet: req.body['userData[pet]']

    }).then(function(dbUser) {
      res.json(dbUser);
    });

    db.Profession.create({

      category: req.body['professionData[category]']

    }).then(function(dbProfession) {
      res.json(dbProfession);
    });

  });
};

Solution

  • You need to save the profession data once your create user process is completed. Save profession inside the then.

    module.exports = function (app) {
        // POST route for saving a User
        app.post("/api/members", function (req, res) {
            console.log(req.body);
            let tmpJson = {};
    
            db.User.create({
                first_name: req.body['userData[first_name]'],
                last_name: req.body['userData[last_name]'],
                email: req.body['userData[email]'],
                password: req.body['userData[password]'],
                gender: req.body['userData[gender]'],
                pet: req.body['userData[pet]']
            }).then(function (dbUser) {
                tmpJson.dbUser = dbUser;
                return db.Profession.create({
                    category: req.body['professionData[category]']
                });
            }).then(function (professionData) {
                tmpJson.professionData = professionData;
                res.status(200).json({
                    status: "success",
                    reason: tmpJson
                });
            });
        });
    };
    

    You can also use the following approach to save your data.

    exports.createUserAndPrfession = function (req) {
        return models.user.create(
            {
                first_name: req.body['userData[first_name]'],
                last_name: req.body['userData[last_name]'],
                email: req.body['userData[email]'],
                password: req.body['userData[password]'],
                gender: req.body['userData[gender]'],
                pet: req.body['userData[pet]'],
    
                Profession: [{
                    category: req.body['professionData[category]']
                }]
            }, {
                include: [Profession]
            });
    }