When I associate two models, how do I prevent name collisions?
// Find all projects with a least one task where task.state === project.state
Project.findAll({
include: [{
model: Task,
where: { state: Sequelize.col('project.state') }
}]
})
In this example, what if there was a name property in both project and task.
Related
Here's my case.
I'm building a system in which you have users (consider them admins) that create employees and a performance report is created for every employee. The users can only view employees that were created by users from the same company. However, another company can create a report for an employee from a different company using a search field. Once a report is created for that employee, then they can view that employee within the employees list, if the report is not there, they wouldn't have seen it within that list.
Note: The model names are changed but have same characteristics
I'm trying to have an endpoint which returns all employees based on either of these two scenarios:
Return all employees created by the user which their company belong to the same company as the user initiating the request.
Return all employees that (if they don't belong to the same company as the user who created the employee) have a report associated to them and the report was created by a user from the same company as the user initiating the request.
Here's a brief ERD that explains the relationship between the models:
Here's the code which uses nested joins:
async function getAll(company) {
return await Employee.findAll({
where: {
[Op.or]: [
{
'$User.company$': { [Op.eq]: company }
},
{
'$Report.User.company$': { [Op.eq]: company }
}
]
},
include: [
{
attributes: [],
model: User.scope('withoutPassword'),
},
{
attributes: [],
model: Report,
include: {
attributes: [],
model: User.scope('withoutPassword'),
}
}
]
})
.then(employees => {
return employees
});
}
How to remove some fields of model from find* (Like password, token)?
I think overriding toJSON() function (Like here https://stackoverflow.com/a/27979695/6119618) is not a good way, because i sometimes need this field for password validation or token for checking etc..
Is there something like as .select('+token') as mongoose has?
And another question i think it's fit this topic.
How to remove generated by through fields from find* output?
When i call User.find() it responds { id: 0, name: 'somename', UserProjectsTie: { /* complex object of many-to-many relation table */ } }
To exclude an attribute from find*:
Model.findAll({
attributes: { exclude: ['baz'] }
});
To make this the default behavior, use a scope:
const Model = sequelize.define('Model', {
// Attributes
}, {
defaultScope: {
attributes: { exclude: ['baz'] }
}
});
Unless I'm mistaken the 'through' should only show up when using 'include'. To get rid of through in that case:
Model.findAll({
include: [{association: 'OtherModels', through: {attributes: []}}]
});
I'm currently working on a project where I have 3 models with a child and parent structure.
City has multiple Locations which has multiple Stones. Each Stone only has one Location as parent and each Location only has one City as parent.
Now, I want to create a list of all Stones that 'belong' (through a Location) to a specific City. How would I retrieve all these associations, without having to do the following:
City.find({
where: {
id: 1337
},
include: [{
model: Location,
include: [{
model: Stone
}]
}]
})
.then((city) => {
city.stones = [].concat.apply([], city.locations.map(location => location.stones));
});
I'm trying to find out if there's a "SQL only" solution, so not retrieving data / having to execute JavaScript to generate this array.
When I define a relation, I specify what model object it is related to:
models.Guest.belongsTo(models.Member, {foreignKey: 'guestId', as: 'guest'});
Now to use this relationship in a query, I need to specify the model object again:
Guest.findAll({
include: models.Member,
as: 'guest'
});
In my setup, all the relationships are defined in a single file, while individual models are in files by themselves. The setup defines the models object, which has all of them - and the thing is available to application logic.
What I would like is define some of the more complex queries directly in the Guest model object, to abstract them away from the application. To do this, I'd like to find the models.Member object - retrieving it somewhere out of the relationship:
Guest.findMembers = function(){
return this.findAll({
include: <that model that guest is related to>,
as: 'guest'
});
}
Please imagine that the example is complex enough that it warrants solving. Lots more other joins and where statements, for instance. Or data processing after the fact.
I can pass the models object into the setup of each individual object, so its siblings can be accessed. Is that my only option?
You can just also add an include in your include mode also
Guest.findMembers = function(){
return this.findAll({
include: [{
model: <that model that guest is related to>,
as: 'guest',
include: [{
model: <that model that guest is related this included model>,
as: 'setTheAlias',
}]
}]
});
}
I have a model which contains relationships between a user and his contacts.
Here is the current code for this model :
module.exports = {
connection: 'mysqlServer',
attributes: {
user: {
model: 'user',
required: true
},
contact: {
model: 'user',
required: true
}
}
};
What I would like is to make the combo user and contact uniques. That means that there may be several identical users and several identical contacts but only one user with a specific contact (ie: we can have user=1, contact=1 and user=1, contact=2, but we can't have user=1, contact=1 and user=1, contact=1).
The unique validation property is not enough to create the validation I want.
Do you have an idea how I should proceed? With custom validation rules maybe?