I have two models, named users and messages. It's basically a chat application. The models are associated as below:
User.hasMany(Message);
Message.belongsTo(User);
User-> id, name, pic
Message-> id, text, timestamp, user_id (foreign key)
I want to get a list of users who has recently messaged. Here is what I've tried:
DB.User.findAll({
include: [{
model: DB.Message,
order: [
['timestamp', 'DESC']
],
limit: 1
}]
});
The SQL Query may look like this:
SELECT U.first_name, user_id, MAX(timestamp) FROM messages M, users
U WHERE M.user_id=U.id GROUP BY user_id
Try this
DB.User.findAll({
include: [ { model: DB.Message, required: true,order:['id','DESC']}]
});
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
});
}
I'm using sequelize to handle SQLite database used by Electon app. Application let the user search for music based on selected topics, moods and so on.
I'm trying to build search mechanism that allow to select multiple moods and the function should return tracks that have all of the selected moods
Here is mentioned above database simplified model:
Also the sequelize relation between models are set
db.moods.belongsToMany(db.tracks, {
through: db.moodsTracks,
foreignKey: 'uuid',
});
db.tracks.belongsToMany(db.moods, {
through: db.moodsTracks,
foreignKey: 'trackId',
});
db.moods.hasMany(db.moodsTracks, {foreignKey: 'uuid'});
db.tracks.hasMany(db.moodsTracks, {foreignKey: 'trackId'});
Now I'm trying to find all tracks that contain has specific moods
let tracks = await db.tracks.findAll({
include: [{
model: db.moods,
required: true,
where: uuid: {
[Op.and]: ['MOOD-UUID-1', 'MOOD-UUID-2']
}
}],
})
(first try fail)
I have tried to log generated by sequelize code and its returns:
INNER JOIN `moodsTracks` AS `moodsTracks` ON `tracks`.`id` = `moodsTracks`.`trackId`
AND (
`moodsTracks`.`uuid` = 'MOOD-UUID-1'
AND `moodsTracks`.`uuid` = 'MOOD-UUID-2'
)
Then I have try to build raw SQLite query
SELECT
COUNT(trackid),
*
FROM
`tracks` AS `tracks`
INNER JOIN `moodstracks` AS `moodsTracks` ON `tracks`.`id` = `moodstracks`.`trackid`
WHERE
(
`moodsTracks`.`uuid` = 'MOOD-UUID-1'
OR `moodsTracks`.`uuid` = 'MOOD-UUID-2'
)
GROUP BY
(`moodsTracks`.`trackId`)
HAVING
COUNT(trackid) = 2;
I'm aware that isn't great solution, but it works in SQL console.
Questions:
Is there any other way to solve that kind problem? Maybe I use AND operator wrongly
If not, I will try to implement that SQL code above.
Is there any documentation for HAVING keyword in sequelize, i didn't found any thing like this on official web page
Why are you using [Op.and] when in your raw query you are using 'OR'?
This solution works for me:
let tracks = await db.tracks.findAll({
include: [db.moods],
group: 'moodsTracks.trackId',
include: [{
model: db.moods,
where: {
uuid:['UUID1', 'UUID2']
},
having: ["COUNT(DISTINCT moodsTracks.uuid) = 2"]
}]
})
I have a model Booking, which is having hasMany relation with hotels, and hotel is having one to one relation with supppliers.
What i need is, get all booking where supplier_id = 33333.
I am trying this
BOOKINGS.findAll({
where: {
'hotels.supplier.supplier_id' : '32',
},
include: [
{
model: HOTELS,
include: [
{
model: SUPPLIERS,
],
}
],
limit : 30,
offset: 0
})
It throws error like hotels.supplier... column not found.. I tried all things because on docs of sequelze it only gives solution to add check which adds where inside the include which i can't use as it adds sub queries.
I don't want to add where check alongwith supplier model inside the include array, because it adds sub queries, so If i am having 1000 bookings then for all bookings it will add sub query which crashes my apis.
I need a solutions like this query in Sequelize.
Select col1,col2,col3 from BOOKINGS let join HOTELS on BOOKINGS.booking_id = HOTELS.booking_id, inner join SUPPLIERS on BOOKINGS.supplier_id = SUPPLIERS.supplier_id
Adding a where in the include object will not add a sub query. It will just add a where clause to the JOIN which is being applied to the supplier model. It will not crash your API in anyway. You can test it out on your local machine plenty of times to make sure.
BOOKINGS.findAll({
include: [
{
model: HOTELS,
include: [
{
model: SUPPLIERS,
where: { supplier_id: 32 }
}
]
}
],
limit: 30,
offset: 0
})
If you still want to use the query on the top level you can use sequelize.where+ sequelize.literal but you will need to use the table aliases that sequelize assigns. e.g this alias for supplier table will not work hotels.supplier.supplier_id. Sequelize assings table aliases like in the example I have shown below:
BOOKINGS.findAll({
where: sequelize.where(sequelize.literal("`hotels->suppliers`.supplier_id = 32")),
include: [
{
model: HOTELS,
include: [SUPPLIERS]
}
],
limit: 30,
offset: 0
})
I have model answerlist which has ownerId and answeredBy objects containing ownerId.
I want to fetch answerlist's data where ownerId = answeredBy.ownerId.
Don't know how to do it in sequelize.
Following is my code
db.answersList.findAll({
include: [
{ model: db.Employee, as: 'answeredBy', attributes: ['id', 'ownerId']},
{ model: db.Owner, as: 'owner',attributes: ['id']}
],
want to do something like where:{'answeredBy.ownerId':'owner.id'}
});
I have an instance where I have Users and Roles. I have the following:
var User = sequelize.define("Users", {
username: DataTypes.STRING,
password: DataTypes.STRING,
});
var Role = sequelize.define("Role", {
role: DataTypes.STRING
});
var UsersRole = sequelize.define("UsersRole");
User.belongsToMany(Role, {through: UsersRole});
Which creates a UsersRoles table in the DB for me with a UserId and RoleId column. This is all working fine, but now I want to be able to update a users role, I can't work out quite how to do this! I've tried the following with no luck so far:
models.Users.findAll({
where: { id: req.params.id },
include: [{ all: true }]
}).then(function(dbUser){
dbUser[0].Roles[0].updateAttributes({
RoleId: req.body.role,
},
{
where: { UserId : req.params.id }
}
).then(function (result) {...
In summary, all I want to do is be able to change a users role, so update the 'UsersRoles' table and change the RoleId for a given UserId. I can't quite seem to figure out how to get to the UsersRoles table via any sequelize syntax!
I could write some raw SQL but that doesn't feel right?
EDIT
I just want to update a users role, if the table has:
| UserId | RoleId |
-------------------
| 1 | 1 |
I would like to be able to change it to:
| UserId | RoleId |
-------------------
| 1 | 2 |
but I can't quite figure out the code to do this!
There is no need to interact with the join table directly - You can simply do
user.setRoles([newRole]);
http://docs.sequelizejs.com/en/latest/api/associations/belongs-to-many/#setassociationsnewassociations-options-promise
Notice that I'm passing an array, since users can have many roles - set removes all currently assigned roles. If you want to add a new role and keep the existing, use
user.addRole(newRole);
you are updating RoleId but you have not defined it. If you don't define a primary key on a table the by default Sequelize defines a primary key by name if id, so you should do id: req.body.role.