How do I convert a SQL query for Sequelize? - sql

I have a SQL query (using mysql as DB) that I now need to rewrite as a sequelize.js query in node.js.
SQL Query
SELECT p.UserID, SUM(p.score), u.username
FROM Picks p
LEFT JOIN Users u
ON p.UserId = u.id
GROUP BY p.UserId;
not quite sure how this query needs to be structured to get the same results with sequelize.

This should do what you're needing:
db.Pick.findAll({
attributes: [
'UserID',
[db.sequelize.fn('SUM', db.sequelize.col('score')), 'score']
],
include: [{
model: db.User,
required: true,
attributes: ['username']
}],
group: ['UserID']
}).then((results) => {
...
})

Maybe try this (I assume you already associate Picks and Users), and you can access user.name by pick.user.username:
Picks.findAll({
attributes: ['UserID', [sequelize.fn('SUM', 'score'), 'sumScore']]
groupBy: ['UserID']
include: [
model: Users
]
});

The website at this domain no longer provides this tool. It's now filled with ads and likely malware.
I know this question is old but this answer may help others.
I have found an online converter that can convert raw SQL to Sequelize.
The link is https://pontaku-tools.com/english/
When converted from this site I got the following reponse.
Picks.hasMany(Users,{foreignKey: '', as: 'u'});
var _q = Picks;
_q.findAll({
include: [{model: Users, as: 'u', required: false,}, ],
attributes: [[sequelize.fn('SUM', sequelize.col('p.score')), 'p.score'],['p.UserID', 'p.UserID'],['u.username', 'u.username']],
group: [''],
});

Writing a sql query may not always be very simple with sequelize functions. Sometimes I recommend to run your plain sql query by combining it with this function.
const { QueryTypes } = require('sequelize');
async message_page (req,res) {
const messagePage = await db.query("SELECT * FROM ..", { type: QueryTypes.SELECT });
return messagePage;},

Related

Is there a way to run the supplied prisma query as a raw sql query?

I have been stuck with this and similar dilemmas for a while now and can't seem to find an acceptable solution. Prisma currently doesn't allow for upsertMany in it's queries, or in my case a nested upsertMany. I have found some accepted solutions and the most popular one is using $transaction from prisma to write a loop of upserts which doesn't work for me as each query contains up to 200 items to upsert (currently testing 100 items takes roughly 10sec to run so it really isn't an acceptable solution). Prisma offers the ability to use $queryRaw to use a raw SQL query which may offer a more acceptable solution. I've supplied the code to their currently accepted solution as well as the query (that isn't currently possible) that I'm hoping someone could help me turn into a raw sql query or a better solution.
Their accepted solution:
prisma.$transaction(data.map((d) =>
prisma.MODEL.upsert({
where:{
id: d.id
},
update:{
foo:d.foo,
},
create:{
foo: d.foo,
bar: d.bar
},
}),
),
);
How I would need to implement it as I would like to create one MODEL with a related array of MODELS and another array of related MODELS:
let transactionOne = prisma.$transaction(
arrayOne.map((d)=>
prisma.MODEL.upsert({
where:{
id: d.id,
},
update:{
foo: d.foo,
},
create:{
foo: d.foo,
bar: d.bar,
},
}),
)
);
let transactionTwo = prisma.$transaction(
arrayTwo.map((d)=>
prisma.MODEL.upsert({
where:{
id: d.id,
},
update:{
foo: d.foo,
},
create:{
foo: d.foo,
bar: d.bar,
},
}),
)
);
let data = await prisma.MODEL.create({
data:{
foo: foo,
bar: bar,
example:{
connect: transactionOne.map((a)=>({id: a.id})),
},
exampleTwo:{
connect: transactionTwo.map((b)=>({id: b.id})),
},
},
});
My example above like mentioned before takes just over 10 seconds with 100 items and may possibly require 200 items so 20 seconds per call. Is there an easier way to make this faster or like I said a way to create a raw SQL query with the same results?
Thanks for any help!

BookshelfJS - 'withRelated' through relational table returns empty results

I've been trying to structure the relations in my database for more efficient querying and joins but after following the guides for '.belongsToMany', '.through' and '.belongsTo' I'm now getting empty results.
I've got a Sound model and a Keyword model which I want to model with a many-to-many relationship (each Sound can have multiple Keywords, and each Keyword can be related to multiple sounds). Based on the documentation '.belongsToMany' would be the relation to use here.
I've set up my models as follows, using a 'sound_keyword' relational table/SoundKeyword relational model (where each entry has it's own unique 'id', a 'soundID', and a 'keywordID'):
var Sound = bookshelf.Model.extend({
tableName: 'sounds',
keywords: function () {
return this.belongsToMany(Keyword, 'sound_keyword', 'id', 'id').through(SoundKeyword, 'id', 'soundID');
},
});
var Keyword = bookshelf.Model.extend({
tableName: 'keywords',
sounds: function () {
return this.belongsToMany(Sound, 'sound_keyword', 'id', 'id').through(SoundKeyword, 'id', 'keywordID');
}
});
where:
var SoundKeyword = bookshelf.Model.extend({
tableName: 'sound_keyword',
sound: function () {
return this.belongsTo(Sound, 'soundID');
},
keyword: function () {
return this.belongsTo(Keyword, 'keywordID');
}
});
From what I've read in the docs and the BookshelfJS GitHub page the above seems to be correct. Despite this when I run the following query I'm getting an empty result set (the Sound in question is related to 3 Keywords in the DB):
var results = await Sound
.where('id', soundID)
.fetch({
withRelated: ['keywords']
})
.then((result) => {
console.log(JSON.stringify(result.related('keywords')));
})
Where am I going wrong with this? Are the relationships not set up correctly (Possibly wrong foreign keys?)? Am I fetching related models incorrectly?
Happy to provide the Knex setup as needed.
UPDATED EDIT:
I had been using the Model-Registry Plugin from the start and had forgotten about it. As it turns out, while the below syntax is correct, it prefers syntax similar to the following (i.e. lowercase 'model', dropping the '.extends' and putting model names in quotes):
var Sound = bookshelf.model('Sound',{
tableName: 'sounds',
keywords: function () {
return this.belongsToMany('Keyword', 'sound_keyword', 'soundID', 'keywordID');
},
});
var Keyword = bookshelf.model('Keyword',{
tableName: 'keywords',
sounds: function () {
return this.belongsToMany('Sound', 'sound_keyword', 'keywordID', 'soundID');
}
});
Hope this can be of help to others.
Seems like removing the '.through' relation and changing the IDs in the '.belongsToMany' call did the trick (as below), though I'm not entirely sure why (the docs seem to imply belongsToMany and .through work well together - possibly redundant?)
var Sound = bookshelf.Model.extend({
tableName: 'sounds',
keywords: function () {
return this.belongsToMany(Keyword, 'sound_keyword', 'soundID', 'keywordID');
},
});
var Keyword = bookshelf.Model.extend({
tableName: 'keywords',
sounds: function () {
return this.belongsToMany(Sound, 'sound_keyword', 'keywordID', 'soundID');
}
});
I did try my original code with soundID and keywordId instead of 'id' (as below), but without the .through relation and that gave the same empty results.

Pagination with Sequelize using limit takes 4 times longer to load. How can I optimize?

I am currently using Sequelize with Node.js and I wanted to incorporate pagination. The code works, however, Sequelize takes 4 times more time to load than what it used to. 13 seconds is not acceptable as a loading time for each page. I tried both findAll and findAndCountAll, but as soon as I add the limit to the options, it becomes really slow. Here is the query used in node.js:
return req.models.BookingGroup.findAndCountAll({
attributes: group_attrs,
where: group_where,
include: [
{
model: req.models.Booking,
attributes: book_attrs,
where: booking_where,
include: [
{
model: req.models.Guest,
attributes: [
'id',
'firstname',
'lastname',
'email',
],
},
],
}
],
offset,
limit
})
.then(({count, rows}) => {
res.send(200, {count, groups: rows})
return {count, groups: rows}
})
.catch(err => console.log("##error ", err))
Am I doing something wrong? It only returns 70 entries, I don't think it should take this long. I haven't found anything online, and I don't know if it is a problem with Sequelize but any help is appreciated !
I came across a performance issue when using findandcountall.
In my case, Sequelize formed a lengthy JOIN statement in findandcountall (You can check this with passing the option logging: console.log).
However, instead of using findAndCountAll, I used .count() to get the number and .findAll() to get the results. This actually turned out to be much faster than using the findAndCountAll().
const count = await req.models.BookingGroup.count({
where, include, distinct: true, ...
});
const bookingGroup = await req.models.BookingGroup.findAll({
where, include, attributes, limit, offset, ...
});
res.send({ bookingGroup: [], count });

Missing left join when using bookshelf/knex

for some reason, in some cases knex doesn't add left join to the query. I tried to reproduce the bug with minimal code, So I tried to use knex with in-memory sqlite3.
var knex = require('knex')({
client:'sqlite3',
connection: {
filename: ":memory:"
},
debug: true
});
var bookshelf = require('bookshelf')(knex);
var Conversation = bookshelf.Model.extend({
tableName: 'conversations',
});
Conversation
.where(qb => {
qb
.leftJoin('conversations_recipients', function () {
this.on('conversations_recipients.conversationId', 'conversations.id');
});
})
.fetch();
When I check the debug messages on the console, I get:
{ method: 'select',
options: {},
bindings: [ 1 ],
sql: 'select "conversations".* from "conversations" limit ?' }
And there's the left join is missing. Someone knows what's wrong with this code, and how can I include the desired join?
Thanks in advance.
You're calling where instead of query. Also you don't need to use the join callback unless you're doing complex join logic. Refer to knex documentation for where and join. And Bookshelf documentation for query
Conversation.query(qb =>
qb.leftJoin(
'conversations_recipients',
'conversations_recipients.conversationId',
'conversations.id'
);
).fetch().then(conversations => { // ...

Rally query Projects/SubProjects

I'm trying to query for all the projects in the workspace, which I can. But when I try to query for a specific project, I get 0 results.
If I just query for projects, I get a full list. If I take one of those results and add in a:
query: 'Project.Name="Whatever"',
I get 0 results.
Full code:
//Works
var queryConfig = {
type: 'project',
key: 'projects',
fetch: 'Name'
};
rallyDataSource.findAll(queryConfig, showStories);
And then
//Doesn't work
var queryConfig = {
type: 'project',
key: 'projects',
query: 'Project.Name = "Iron Horse"',
fetch: 'Name'
};
rallyDataSource.findAll(queryConfig, showStories);
If I can figure this out, I'm also trying to get a list of all the child projects to that 1 project. I am having no success in that regard either, but I belive to even do that I'd need my first query to work.
I believe this query param will get you what you want:
query: '(Name = "Iron Horse")',