I have two SQL queries which i am having trouble with converting to Sequelieze Queries.
I have a model named UserTeam having columns id,team_id and isAdmin.
The first query is
Select distinct('team_id') from UserTeam where id==user.id and idAdmin==true
The second one is similar by with a little addition of group by
Select count('isAdmin') from UserTeam where id==user.id group by 'team_id';
I have written this but is incorrect:
const teamsMember = await UserTeam.findAll({where: { id: user.id, isAdmin : true}, sequelize.fn('distinct', sequelize.col('UserTeam.team_id'))});
const adminCount = await UserTeam.findAll({where: {id: user.id }, sequelize.fn('count',sequelize.col('isAdmin')), group: ['UserTeam.team_id']]});
And is there any way to get the generated query from these sequelize queries?
Related
I am new to sequelize. I am not sure how to convert this MySql query so that I can use it in my node.js file.
MySql query:
SELECT Rtrim(Ltrim(childstatus)),TIMESTAMPDIFF(d,dob,now(3))
INTO #childstatus, #Ageday
FROM childdetails where registno=#registno
I have sequelize model for childdetails. I am not sure how to structure this query.
You can use Sequelize.fn to call these two functions indicating them in attributes option like this:
const details = await ChildDetials.findAll({
attributes: [
[Sequelize.fn('RTrim', Sequelize.fn('LTrim', Sequelize.col('childstatus'))), 'childsttaus'],
[Sequelize.fn('TIMESTAMPDIFF', Sequelize.literal('d'), Sequelize.col('dob'), Sequelize.fn('now', 3)), 'Ageday']
],
where: {
registno: registno
}
})
I have got 3 entities in my database, we can imagine these 3(I kept only important columns)
User
#PrimaryColumn()
nick: string
#OneToMany(type => Connection, connection => connection.user)
connections:Connection[]
Connection
#PrimaryGeneratedColumn()
id: number;
#ManyToOne(type => User,user => user.connections)
user: User;
#ManyToOne(type => Stream)
stream: Stream;
Stream
#PrimaryGeneratedColumn()
id: number;
I think that I have some skills with building Queries in typeorm, but I am stucked right now on using subquery.
What I want to do?
Join all User entites on part of Connection entites(Select few of Connection entities as subquery => make leftJoin User-subquery => filter results to get connections which didnt find right(Connection) side so Connection ID is NULL ).
What I tried?
let query = await connectionRepository
.createQueryBuilder('connection')
.subQuery()
.where("connection.id = :id",{id:1})
.select(['connection.id','connection.user AS nick'])
.getQuery();
const result = await userRepository.createQueryBuilder("user")
.leftJoinAndSelect("user.permissions", '(' + query + ')')
.where("user.nick = :nick")
.andWhere(`(${query}).id is null`)
.getMany();
I also tried to use subquery without .getQuery() but It didnt work anyway, I think that I can write Ok subquery, but then I have problem to use it in the second query(with subquery attributes etc.)
I have also seen some examples with lambda functions, but lambda was always on first position in the leftJoin.
Thank you for your answer:)
You need something like that:
const result = await userRepository.query(`
SELECT user.* FROM user
LEFT JOIN connection connection ON user.id = connection.user_id
WHERE connection.user_id IS NULL
AND connection.id = ?;
`, [id])
Related question: MYSQL Left Join how do I select NULL values?
I'm working with two tables in particular. Users and Friends. Users has a bunch of information that defines the User whereas Friends has two columns aside from id: user_id and friend_id where both of them are a reference to the User table.
I'm trying to find all of the users friends in as little calls to the db as possible and I currently have 2. One to retrieve the id of a user first from a request, then another to Friends where I compare the IDs from the first call and then a third call that passes the array of friends and find all of them in the Users table. This already feels like overkill and I think that with associations, there has to be a better way.
Modification of the tables unfortunately is not an option.
One thing that I saw from "http://docs.sequelizejs.com/manual/querying.html#relations---associations"
I tried but got an interesting error.. when trying to repurpose the code snippet in the link under Relations/Associations, I get "user is associated to friends multiple times. To identify the correct association, you must use the 'as' keyword to specify the alias of the association you want to include."
const userRecord = await User.findOne({
where: { id }
})
const friendsIDs = await Friends.findAll({
attributes: ["friend_id"],
where: {
user_id: userRecord.id
}
}).then(results => results.map(result => result.friend_id));
const Sequelize = require("sequelize");
const Op = Sequelize.Op;
return await User.findAll({
where: {
id: { [Op.in]: friendsIDs }
},
});
Above for my use case works. I'm just wondering if there are ways to cut down the number of calls to the db.
Turns out Sequelize handles this for you if you have the proper associations in place so yes, it was a one liner user.getFriends() for me.
So, I'm using sequelize with a mysql instance and I have this hierarchy : a task has n images and also n metadata key value pairs.
I want to get all images based on userId column of task, and afterwards get them grouped by 'createdAt' column taking into consideration the day, since a normal groupby will be pointless ( no objects share the same datetime ). I did lots of test to try to group, and I ended up using this query, which gives bad results ( I have like 11 images for a task, and it retrieves 4 ). Honestly, i don't know what I'm doing wrong. Any of you have any idea?
This is the code snippet:
var userId = security.utils.getKeycloakSubject(req);
var where = {
userId: userId
};
db.image.findAll({
include: [{
model: db.task,
include: [{
model: db.metadata,
as: 'metadata'
}],
where: where
}],
group: [db.Sequelize.fn('DAY', db.Sequelize.col('image.createdAt'))]
}).then(function (images) {
return res.json(images);
}, function (error) {
return res.status(500).json(error);
})
I saw your question and also found this: Sequelize grouping by date, disregarding hours/minutes/seconds
It is a question about group the DAY(createdAt), looks similar with yours.
And my solution of GROUP BY DAY() is look like:
item.findAll({
attributes:
[[sequelize.fn('DATE_FORMAT', sequelize.col('TimeStamp'), '%H'), 'dates']],
group: [sequelize.fn('DAY', sequelize.col('TimeStamp'))]
}).
then(function(result){console.log(result)
}).
catch(function(error){}).catch(function(error) {
console.log(error);
});
So the raw SQL likes: SELECT DATE_FORMAT('TimeStamp', '%H') as 'dates' FROM tableName GROUP BY DAY('TimeStamp');
Hope it helps you, or you can show us the SQL you want to use, maybe it is easier to help you too.
Good luck.
I'm using mssql together with node-sql to build SELECT queries but I can't find any example how to use it to build UPDATE queries. I have an object where properties corresponds to table fields and I would like to update all of them.
Assume:
child: sql.define({
name: 'children',
columns: ['id', 'name', 'surname', 'group']
})
and:
var data = {/*new child data*/};
var query = child.update(data).where(child.id.equals(data.id)).toQuery().text;
How can I use this with mssql without knowing values and count of data properties?
Right now I have this:
connection.query(query, [data.id, data.name, data.surname, data.group], function(err, result) {
res.redirect('/index');
});
that can be achieved by using lodash's values:
_.values(data);
which returns array of object properties but it does not guarantee correct order which is deal breaker.
How can I tackle that problem?
This will return an array of values based on the order of table columns:
child.columns.map(function(col){return data[col.name]})
It might be possible to compact the above in shorter form with lodash.
Few days later I figured node-sql's query object also has .values property besides .text property so above update can be written as
var data = {/*new child data*/};
var query = child.update(data).where(child.id.equals(data.id)).toQuery();
connection.query(query.text, query.values, function(err, result) {
res.redirect('/index');
});