Sequelize performs extra SELECT query before updating associations - javascript

Sequelize seems to introduce unnecessary queries when adding new associated record to a source record.
For example, consider a regular many-to-many association with a Users model and a Groups model, where a user belongsToMany groups, and each group belongsToMany users.
If I create a new user record, then add two existing groups to that user, Sequelize executes what seems to be an extra unnecessary
SELECT` query:
const record = await Users.create({id: 1, name: 'John'})
await record.addGroups([2,3]);
The above call to record.addGroups([2,3]) leads to these two MySQL queries:
SELECT group_id
, user_id
,
FROM user_groups
WHERE user_groups.user_id = 1
AND user_groups.group_id IN ('2', '3');
INSERT INTO user_groups (group_id,user_id) VALUES
('2','1'),('3','1');
1) What is the cause of the first SELECT query above?
2) Are there any benefits including that query?
3) Are there any ways to disable this extra SELECT query?

Related

SQLite table is only able to hold 1 row?

So, I have 2 tables, that I've added per the documentation, but something weird happens whenever I try to add a row to them. The data is written into the .db file, but whenever I query it, it only returns the first row. I can still update, and read these rows normally, but any data I write to them, just doesn't update the table. It's only the first row that get's written.
I've looked over all my statements, and I know they're right, since the first statement adds it to the table, but the second doesn't. I'm using the base configuration of sqlite3 from npm, per the docs, so I don't know what I'm doing wrong.
I don't have any errors, and the expected result, is that I'm able to add as many rows as I can
db.serialize(function() {
db.run("CREATE TABLE users (userId int, user varchar(255))");
db.run("CREATE TABLE notes (userId int, uuid varchar(50), name varchar(255), noteData varchar(1024), file BLOB(21845))")
});
db.run("INSERT INTO users (userId, user) VALUES (0, 'User')")
db.run(`INSERT INTO notes (userId, uuid, name, noteData) VALUES (0, 'uuid', 'First Note','This will be readable.')`)
//This statement will add the data to the file, but the query won't read it.
db.run(`INSERT INTO notes (userId, uuid, name, noteData) VALUES (1, 'uuid2', 'First Note','This will not show.')`)
db.get("SELECT * FROM notes",[],(err,row)=>{console.log(row)})
Also, this is not an asynchronous problem. In the example, I added the last line, but it's not actually in my code. I'm requesting it minutes later, and I can confirm the text is in the database, it just decides not to read it.
Your second insertion into notes table looks like has syntax error because of using additional single-quote.
I've changed by using two single-quotes at db-fiddle.com and it's working, but i'm not sure why you don't get an exception.
INSERT INTO users (userId, user) VALUES (0, 'User');
INSERT INTO notes (userId, uuid, name, noteData) VALUES (0, 'uuid', 'First Note','This will be readable.');
INSERT INTO notes (userId, uuid, name, noteData) VALUES (1, 'uuid2', 'First Note','This won''t.');
SELECT * FROM notes;
Ref for using two single-quotes; https://www.sqlite.org/faq.html#q14
Turn out I needed to use db.all. db.get returns only the first row.

How to use LAST_INSERT_ID() to INSERT multiple records with the same value

So most questions about LAST_INSERT_ID() with multiple INSERT records involve getting multiple IDs back after the insert, my question is backwards from that.
I have table foo, with a many-to-many relationship with bar, and a junction table, foo__bar. I want to INSERT a single foo record, but also an unknown quantity of bar associations, so I need the LAST_INSERT_ID() after the first INSERT statement, but multiple times:
const db = require('mysql');
...
//connection and pooling set up
let sql = `INSERT INTO foo VALUES(null, ?, ?);
INSERT INTO foo__bar((LAST_INSERT_ID(), ?), (LAST_INSERT_ID(), ?)//etc
`;
let barIds = [1,4];
let params = [name, description, barIds[0], barIds[1]];
let result = await db.query(sql, params);
This works fine if the bar table is already populated and the bar ids are valid, and I only ever do two associations per INSERT:
--table foo__bar
+------+------+
|foo_id|bar_id|
|------|------|
| 1| 1|
|------|------|
| 1| 4|
+------+------+
But what if I have multiple values/associations? Using the 'mysql' npm package, normally I could just do this and an array will be converted into ((val1, val2),(val1, val2),(val1,val1)) etc. However, for my junction table, I need val1 to be the same every time, specifically LAST_INSERT_ID(). Is this possible without having to make two async calls to the database?
Thanks

Sequelize.js - subselect in join clause

I have two tables - customer and order with one-to-many relationship. I want to retrieve in a single query all customer data and total value of his orders.
In raw SQL that would be something like this:
select customer.*, o.total from customer
inner join (select sum(value) as total, customer_id from
order group by customer_id) as o
on customer.id=i.customer_id
My question is - how to express this query in Sequelize without writing SQL? Is this even possible?
Try this:
const query = `
SELECT
table_a.table_a_id AS "table_a.table_a_id",
table_b.table_b_id AS "table_b.table_b_id"
FROM
table_a
LEFT JOIN
(SELECT * FROM table_b) AS table_b
ON
table_a.table_b_id = table_b.table_b_id
`;
const options = {
model: models.table_a,
mapToModel: true,
nest: true,
raw: true,
type: sequelize.QueryTypes.SELECT
};
let tableAs = await db.sequelize.query(query, options);
Please note that you need the alias in the select statements. Seems like Sequelize.js differentiates the tables by the dot in the name.
caution: this doesn't work if table_a and table_b has "one to many" relationship because table_bs must be array. This seems like just overwrite table_b without making it array.
Hi xersee first you want to create two tables customer and order in sequalize.js format
Then after summation of value column and customer_id column from table order put it into one table
Then after that just join the new table with customer table in ORM Style
Please refer below link it may be help for you.
How to make join querys using sequelize in nodejs

Using data from 2 queries in order to make a graph

I have three tables in MySQL.
Staff with fields id, name, surname, telephone, adress, id_work.
Work with fields id, name.
Absence with fields id, name, id_staff.
Also,I have the following queries:
Query 1
SELECT COUNT(*)
FROM staff s
INNER JOIN work w ON s.id_work = w.id
LEFT JOIN absence a ON s.id = a.id_staff
WHERE w.name='sales manager'
AND a.name = 'disease'
AND a.id_staff IS NULL;
Query 2
SELECT COUNT(*)
FROM staff s, work w, absence a
WHERE s.id=a.id_staff
AND s.id_work=w.id
AND w.name='sales manager'
AND a.name='disease'.
As it seems, the first query is inverse of second query. I want to make a graph which seems the % of the staff who is active/inactive. I decide to use google graphs and especially 3D pie chart:
https://developers.google.com/chart/interactive/docs/gallery/piechart#making-a-3d-pie-chart
I try to connect mysql with javascript via Ajax but dont work
Do you nhave any other idea in order to make this graph using data from those queries

MongoDB - Query conundrum - Document refs or subdocument

I've run into a bit of an issue with some data that I'm storing in my MongoDB (Note: I'm using mongoose as an ODM). I have two schemas:
mongoose.model('Buyer',{
credit: Number,
})
and
mongoose.model('Item',{
bid: Number,
location: { type: [Number], index: '2d' }
})
Buyer/Item will have a parent/child association, with a one-to-many relationship. I know that I can set up Items to be embedded subdocs to the Buyer document or I can create two separate documents with object id references to each other.
The problem I am facing is that I need to query Items where it's bid is lower than Buyer's credit but also where location is near a certain geo coordinate.
To satisfy the first criteria, it seems I should embed Items as a subdoc so that I can compare the two numbers. But, in order to compare locations with a geoNear query, it seems it would be better to separate the documents, otherwise, I can't perform geoNear on each subdocument.
Is there any way that I can perform both tasks on this data? If so, how should I structure my data? If not, is there a way that I can perform one query and then a second query on the result from the first query?
Thanks for your help!
There is another option (besides embedding and normalizing) for storing hierarchies in mongodb, that is storing them as tree structures. In this case you would store Buyers and Items in separate documents but in the same collection. Each Item document would need a field pointing to its Buyer (parent) document, and each Buyer document's parent field would be set to null. The docs I linked to explain several implementations you could choose from.
If your items are stored in two separate collections than the best option will be write your own function and call it using mongoose.connection.db.eval('some code...');. In such case you can execute your advanced logic on the server side.
You can write something like this:
var allNearItems = db.Items.find(
{ location: {
$near: {
$geometry: {
type: "Point" ,
coordinates: [ <longitude> , <latitude> ]
},
$maxDistance: 100
}
}
});
var res = [];
allNearItems.forEach(function(item){
var buyer = db.Buyers.find({ id: item.buyerId })[0];
if (!buyer) continue;
if (item.bid < buyer.credit) {
res.push(item.id);
}
});
return res;
After evaluation (place it in mongoose.connection.db.eval("...") call) you will get the array of item id`s.
Use it with cautions. If your allNearItems array will be too large or you will query it very often you can face the performance problems. MongoDB team actually has deprecated direct js code execution but it is still available on current stable release.

Categories