Pulling Sequelize Info from multiple tables - mysql

I'm pretty new to new sequelize but I'm trying to figure out how I can pull sequelize information from multiple tables (Place and Review tables) and render them on the same page. The Review table has a User Id and a Place Id. I've tried raw queries and different variations of the code below to no avail. What sort of syntax should I use in this case?
User.hasMany(Review);
Review.belongsTo(User);
User.hasMany(Place);
Place.belongsTo(User);
Place.hasMany(Review);
Review.belongsTo(Place);
app.get('/place/:category/:id', function(req, res){
var id = req.params.id;
Place.findAll({
where : {id : id},
include: [{
model: [Review]
}]
}).then(function(reviews){
res.render('singular', {reviews});
});
});

From your API route definition, I assume you're trying to display reviews for a place based on place ID.
So, to achieve this, you could model your table associations as
Places.hasMany(Reviews);
Users.hasMany(Reviews);
Review.belongsTo(Places);
Review.belongsTo(Users);
Now, based on this association, you could perform the query like this:
Places.findById(req.params.id, {
include: [{
model: Reviews,
required: false,
include: [{
model: Users,
required: false
}]
}]
}).then(function(place) {
// The rest of your logic here...
});

Related

Query model based on value inside one of its columns

I have a sequelize model called staff. One of the staff columns is called locations which holds the id's of all the locations this staff is available at. I want to create a query that uses a Location ID to get all staff active at that location. How can I do that using the ORM?
Assuming I have understood your question correctly and your locations column contains CSV data, then you need to use FIND_IN_SET() -
Staff.findAll({
where: sequelize.where(sequelize.fn('FIND_IN_SET', locationId, sequelize.col('locations')), {[Op.gt]: 0})
})
A better option would be to normalize your data as this query is non-SARGable.
In Sequelize, you can perform a query to filter staff based on their locations using the include and where options in your query.
const staff = await Staff.findAll({
include: [
{
model: Location,
as: 'locations',
where: { id: locationId },
through: { attributes: [] }
}
]
});
const findStaff = await StaffModel.findAll({
where: {
locationId: "your locationId"
}
})

Sequelize - how to get all Employees for all Locations

I'll preface this by saying I think my model associations may be incorrect
Basically what i'm trying to do is is return an array of all Employees for a company.
Get all locations that have the same companyId
With those locations, get all Profiles tied to the locationId.
Profiles are linked to Locations through Employees.
Below is my code.
The query:
Location.findAll({
where: { companyId: user.profile.companyId },
include: [
{
model: Employee
}
]
})
This generates the error "employee is not associated to location!".
My models:
Employee.belongsTo(Profile)
Employee.belongsTo(Location)
Profile.belongsTo(Company)
Location.belongsTo(Company)
Profile.belongsToMany(Location, {
through: Employee,
foreignKey: "profileId"
})
Location.belongsToMany(Profile, {
through: Employee,
foreignKey: "locationId"
})
EDIT:
Adding Location.hasMany(Employee) allows me to do the query however it still requires a for loop within another for loop to get the correct data structure needed.
const locations = await models.Location.findAll({
where: { companyId: user.profile.companyId },
include: [{ model: models.Profile }]
})
const response = []
locations.forEach(location => {
location.profiles.forEach(profile => {
response.push({ location, profile })
})
})
return response
The query below returns what exactly as is however its only for a single location. I need to run the same query but for multiple locations.
Employee.findAll({ where: { locationId }, include: [Profile, Location] })
You've specified that Location belongsToMany Locations, but you've failed to specify the other way around. You should specify that a Location hasMany Employees.
Specifying Employee.belongsTo(Location) allows you to include related Locations with Employees. Specifying Location.hasMany(Employee) allows you to include related Employees with Locations.
I was able to recreate your problem and fix it with this line.
Location.hasMany(Employee, {
//...
})

Sequelize : How to map a custom attribute in a pivot table

I've got this pivot table, which represents a many to many relationship with the models Person and Movie.
The thing is I want to get the role when I call the movies that get the persons associated. I tried this but it doesn't show the role :
models.Movie.findAll({
include: [{
model: models.Person,
as: 'persons',
through: {attributes: ["role"]}
}]
}).then(function(movies) {
res.json(movies);
});
Do I have to specify something in the models for the role ?
I finally managed to achieve this by creating a model for the pivot table movie_person with the role attribute as a string.
var MoviePerson = sequelize.define("MoviePerson", {
role: DataTypes.STRING
},
{
tableName: 'movie_person',
underscored: true
});
Then in my Movie model I added this
Movie.belongsToMany(models.Person, {
through: models.MoviePerson,
foreignKey: 'movie_id',
as: 'persons'
});
I had to do something obviously similar to this in my Person model and that's it !
For the purpose of those who will need this, there is a new method called 'magic methods'. I believe you have declared your many-to-many asociation
const movies = Movie.findAll();
const person = Person.findbyPk(personId);
const moviesPerson = movies.getPersons(person);

Sequelize include (how to structure query)?

I have a query I'm trying to perform based on a one to many relationship.
As an example there is a model called Users and one called Projects.
Users hasMany Projects
Projects have many types which are stored in a type (enum) column. There are 4 different types that potentially a user may have that I want to load. The catch is I want to include the most recent project record (createdAt column) for all networks that potentially will be there. I have not found a way to structure the query for it to work as an include. I have however found a way to do a raw query which does what I want.
I am looking for a way without having to do a raw query. By doing the raw query I have to map the returned results to users I've returned from the other method, or I have to do a simple include and then trim off all the results that are not the most recent. The latter is fine, but I see this getting slower as a user will have many projects and it will keep growing steadily.
This allow serialize a json for anywhere action about a model. Read it, very well
sequelize-virtual-fields
// define models
var Person = sequelize.define('Person', { name: Sequelize.STRING });
var Task = sequelize.define('Task', {
name: Sequelize.STRING,
nameWithPerson: {
type: Sequelize.VIRTUAL,
get: function() { return this.name + ' (' + this.Person.name + ')' }
attributes: [ 'name' ],
include: [ { model: Person, attributes: [ 'name' ] } ],
order: [ ['name'], [ Person, 'name' ] ]
}
});
// define associations
Task.belongsTo(Person);
Person.hasMany(Task);
// activate virtual fields functionality
sequelize.initVirtualFields();

Specifying specific fields with Sequelize (NodeJS) instead of *

Alright so I have a project in NodeJS where I'm utilizing Sequelize for a MySQL ORM. The thing works fantastically however I'm trying to figure out if there is a way to specify what fields are being returned on a query basis or if there's even a way just to do a .query() somewhere.
For example in our user database there can be ridiculous amounts of records and columns. In this case I need to return three columns only so it would be faster to get just those columns. However, Sequelize just queries the table for everything "*" to fulfill the full object model as much as possible. This is the functionality I'd like to bypass in this particular area of the application.
You have to specify the attributes as a property in the object that you pass to findAll():
Project.findAll({attributes: ['name', 'age']}).on('success', function (projects) {
console.log(projects);
});
How I found this:
The query is first called here: https://github.com/sdepold/sequelize/blob/master/lib/model-definition.js#L131
Then gets constructed here: https://github.com/sdepold/sequelize/blob/master/lib/connectors/mysql/query-generator.js#L56-59
Try this in new version
template.findAll({
where: {
user_id: req.params.user_id
},
attributes: ['id', 'template_name'],
}).then(function (list) {
res.status(200).json(list);
})
Use the arrays in the attribute key. You can do nested arrays for aliases.
Project.findAll({
attributes: ['id', ['name', 'project_name']],
where: {id: req.params.id}
})
.then(function(projects) {
res.json(projects);
})
Will yield:
SELECT id, name AS project_name FROM projects WHERE id = ...;
All Answers are correct but we can also use include and exclude as well
Model.findAll({
attributes: { include: ['id'] }
});
Model.findAll({
attributes: { exclude: ['createdAt'] }
});
Source