Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sequelize returns join table in query

I've got a many-to-many relation in my MSQL table between these two model:

  • Venue - Representing a venue which can have multiple owners (employees)
  • Employee - Representing an employee which can be either a ceo or sales employee or whatsoever.

I am using sequelize to set up the relations like so:

Relation Employee > Venue

 Employee.associate = function (models) { 
   models.Employee.belongsToMany(models.Venue, { through: 'EmployeeVenues' })
 }

Relation Venue > Employee

 Venue.associate = function (models) {
    models.Venue.belongsToMany(models.Employee, { through: 'EmployeeVenues' })
 }

Sequelize docs

According to the Sequelize docs it will create a new model called EmployeeVenues with the equivalent foreign keys employee_id and venue_id. Defining through is required. Sequelize would previously attempt to autogenerate names but that would not always lead to the most logical setups. This will add methods getVenues, setVenues, addVenue, addUsers to Employee.


And this is correctly working, when I fire up my Sequelize it creates a new table called EmpoyeeVenues with the correct foreign keys as a compound key. However when I query getVenues it does not return the expected output. Instead, it's returning the associated table values as well, which I don't want.


Query to get all venues belonging to an employee with id equal 1


router.get('/api/v1/users/:employee_id/venues', (request, response) => {
  var employeeId = request.params.employee_id;

  models.Employee.findOne({
    where: {id: employeeId}
  }).then((employee) => {

    if(!employee) { return response.status(400).send("Employee doesnt have a venue registered yet.")}
    var venues = employee.getVenues().then((venues) => {
    response.status(200).send(venues);
  })
})
});

Response Result


[
    {
        "id": 1,
        "capacity": "11",
        "venue_name": "Club Fix",
        "venue_description": "Club in Tilburg",
        "EmployeeVenues": {
            "employee_id": 1,
            "venue_id": 1
        }
    },
    {
        "id": 2,
        "capacity": "400",
        "venue_name": "Club Vie",
        "venue_description": "Club in Rotterdam",
        "EmployeeVenues": {
            "employee_id": 1,
            "venue_id": 2
        }
    }
]

Question

Why is EmployeeVenues included in this query provided by Sequelize? And How can I prevent EmployeeVenues to be included in the response?


Update

According to a issue on the Sequelize github page which was made in 2014 there is a solution that works

https://github.com/sequelize/sequelize/issues/2143

    User.find({
    where: {id: userId}, attributes: userFields,
    include: [
      {model: db.Role, attributes: roleFields, through: {attributes: []}}
    ]
});

But it does not match the documented version in the Sequelize documentation which is up-to-date, at least it should be.


User.findAll({
  include: [{
    model: Project,
    through: {
      attributes: ['createdAt', 'startedAt', 'finishedAt'],
      where: {completed: true}
    }
  }]
});

Or even simple stated on the reference documentation:


user.getPictures() // gets you all pictures
like image 388
Kevin Vugts Avatar asked Dec 24 '17 13:12

Kevin Vugts


2 Answers

Update

According to a issue on the Sequelize github page which was made in 2014 there is a solution that works

https://github.com/sequelize/sequelize/issues/2143

    User.find({
    where: {id: userId}, attributes: userFields,
    include: [
      {model: db.Role, attributes: roleFields, through: {attributes: []}}
    ]
});

But it does not match the documented version in the Sequelize documentation which is up-to-date, at least it should be.


User.findAll({
  include: [{
    model: Project,
    through: {
      attributes: ['createdAt', 'startedAt', 'finishedAt'],
      where: {completed: true}
    }
  }]
});

Or even simple stated on the reference documentation:


user.getPictures() // gets you all pictures
like image 166
Kevin Vugts Avatar answered Oct 20 '22 23:10

Kevin Vugts


I think the answer given lefts out an important thing that's needed- where to keep the attributes which are need from the included model, here - Project. The issue on github has final answer but still not the complete answer which I was looking forward to.

We need to re-specify the attributes at the model level and then make the join table attributes as none

User.findAll({
  include: [{
    model: Project,

    through: 'JoinTableAliasName' /// only if exist/needed
    as: 'modelAssociationAlias' // only if exist/needed

    // attributes needed from Project table
    attributes: ['createdAt', 'startedAt', 'finishedAt'],

    through: { // through again doesn't create any issue
      attributes: [], // this helps removing the join table in returned data
      where: {completed: true}
    }
  }]
});
like image 37
Abhishek Shah Avatar answered Oct 20 '22 22:10

Abhishek Shah