SQL - Nested result instead of merge when left join - mysql

I have a SQL LEFT JOIN like this:
var getEmail = req.body.email;
const connection = require('../conig/db');
let promise = await new Promise((resolve,reject)=>{
connection.query("SELECT users.id, users.account_id, users.email, accounts.id, accounts.company FROM users LEFT JOIN accounts ON accounts.id=users.account_id WHERE users.email = ?",[getEmail], function(err, rows) {
if (err) {
console.log(err);
resolve();
}
console.log('rows:');
console.log(rows);
resolve();
});
});
The result merges the columns:
[{
id: 1,
account_id: '1',
email: 'user01#domain',
company: 'Company 01'
}, {
id: 3,
account_id: '3',
email: 'user02#domain',
company: 'Company 02'
}, {
id: null,
account_id: '',
email: 'user03#domain',
company: null
}]
But what I would like to have is a nested result with the table name at first level like this:
[{
users: {
account_id: '1',
email: "user01#domain",
id: 1
},
accounts: {
company: "Company 01",
id: 1
}
}, {
users: {
account_id: '3',
email: "user02#domain",
id: 2
},
accounts: {
company: "Company 03",
id: 3
}
}, {
users: {
account_id: '',
email: "user03#domain",
id: 3
},
accounts: {
company: null,
id: null
}
}]
How can I achieve this?
I tried:
SELECT users.id AS users.id, users.account_id AS users.account_id, users.email AS users.email, accounts.id AS accounts.id, accounts.company AS accounts.company FROM users LEFT JOIN accounts ON accounts.id=users.account_id
-> Error

Related

trying to group by artist using Sequelize and NodeJs

I have a simple Mysql table like the following fields:
Id, songName, ArtistName, siglosID
example data:
1 My Way Frank Sinatra 1
2 Big Balls ACDC 2
3 New York Frank Sinatra 3
4 Highway To Hell ACDC 4
I want to return an object to return to graphql where data is grouped by artistName
something like the following:
[ artistName: 'ACDC':[
{ id: 2, songName: 'Big Balls', artistName: 'ACDC', siglosId: '2' },
{ id: 4, songName: 'Highway To Hell', artistName: 'ACDC', siglosId: '4' },],
[ artistName: 'Frank Sinatra':[
{ id: 3, songName: 'New York', artistName: 'Frank Sinatra', siglosId: '3' },
{ id: 1, songName: 'My Way', artistName: 'Frank Sinatra', siglosId: '1' },],
]
What I actually get back:
[
{ id: 2, songName: 'Big Balls', artistName: 'ACDC', siglosId: '2' },
{
id: 1,
songName: 'My Way',
artistName: 'Frank Sinatra',
siglosId: '1'
}
Not sure how to use group properly or do I need to use a join?
My code:
getAllSongs: {
type: new GraphQLList(SongType),
async resolve() {
const mytest = await dbSong.findAll({
order: ["artistName"],
group: ["artistName"],
raw: true,
});
console.log("test Songs grouped by artist: ", mytest);
// return dbSong.findAll({ raw: true });
return dbSong.findAll({
order: ["artistName"],
group: ["artistName"],
raw: true,
});
},
},
},
});`

Run a MySQL query on the result of another MySQL query, then push the result of that query into a new array (NodeJS)

I have this function
export const classPerformance = async (req, res) => {
const { classID } = req.body;
db.query(
"SELECT u.userID FROM userIndex u LEFT JOIN classStudent cs ON cs.studentID = u.userID WHERE cs.classID = ?;",
[classID],
(err, result) => {
if (err) {
res.status(500).send("Something went wrong...");
} else {
let parentArr = [
{
user: result,
},
];
let newArr = [];
const dataFetch = parentArr.forEach((data) => {
data.user.forEach((user) => {
db.query(
`SELECT
u.userID AS 'studentID',
u.firstName AS 'firstName',
u.lastName AS 'lastName',
(SELECT COUNT(completionStatus) FROM pacesetterEntries WHERE studentID = ? AND classID = ? AND completionStatus = 'Completed') AS 'Completed',
COUNT(completionStatus) AS 'Total'
FROM
userIndex u
LEFT JOIN pacesetterEntries pe ON u.userID = pe.studentID
WHERE classID = ? AND studentID = ?;`,
[user.userID, classID, classID, user.userID],
(err, results) => {
if (err) {
console.log(err);
} else {
results.forEach((child) => {
newArr.push({
studentID: child.studentID,
firstName: child.firstName,
lastName: child.lastName,
completed: child.Completed,
total: child.Total,
});
});
}
}
);
});
});
dataFetch;
}
}
);
};
The first query returns an array like this:
[ { userID: 244 }, { userID: 245 }, { userID: 250 } ]
For each of those userIDs, the second query is run. The result of that query looks like this:
[
{
studentID: 244,
firstName: 'Test',
lastName: 'Student1',
Completed: 0,
Total: 5
}
]
[
{
studentID: 245,
firstName: 'Test',
lastName: 'Student',
Completed: 1,
Total: 5
}
]
[
{
studentID: 250,
firstName: 'Cameron',
lastName: 'Erasmus',
Completed: 3,
Total: 5
}
]
What I am trying to achieve is getting an array similar to result #2 that I can send back to my frontend for mapping. Exactly like this:
[
{
studentID: 244,
firstName: "Test",
lastName: "Student1",
Completed: 0,
Total: 5,
},
{
studentID: 245,
firstName: "Test",
lastName: "Student",
Completed: 1,
Total: 5,
},
{
studentID: 250,
firstName: "Cameron",
lastName: "Erasmus",
Completed: 3,
Total: 5,
},
];
I've tried to push the result of query 2 into "newArr" but it always comes back empty. Where am I going wrong?

how to count records in prisma io?

I am executing a query but the result of the account adds the letter "n", I don't understand why when I execute the query in mysql console it shows it correctly.
const client = await prisma.$queryRaw`SELECT idClient, COUNT(*) as totalCount FROM sales GROUP BY idClient`;
console.log(client)
executing the same query but in heidiSQL.
Numbers with an n postfix denote the BigInt type in JavaScript MDN. This is probably due to some queryRaw changes that were made in v4.0.0. The Integer results are now being returned as BigInt. You must change your code to handle the new type. See this section of the upgrade guide.
Example: Given this Schema file
model Customers {
id Int #id #default(autoincrement())
customerName String
country String
}
and this script file
async function main() {
await prisma.customers.createMany({
data: [
{
country: 'USA',
customerName: 'John Doe',
},
{
country: 'Germany',
customerName: 'Jane Doe',
},
{
country: 'Canada',
customerName: 'Adams Doe',
},
],
});
const clients = await prisma.customers.groupBy({
by: ['country'],
_count: true,
});
console.log("Using normal client query with groupBy ")
console.log(clients);
const clientsWithRawQuery =
await prisma.$queryRaw`SELECT Country, COUNT(country) as totalCount
FROM Customers GROUP BY Country`;
console.log("\n Using queryRaw")
console.log(clientsWithRawQuery);
console.log(
'Before Conversion: Typeof Count:',
typeof clientsWithRawQuery[0].totalCount
);
clientsWithRawQuery.forEach((countryObject) => {
countryObject.totalCount = Number(countryObject.totalCount);
});
console.log(
'After Conversion: Typeof Count:',
typeof clientsWithRawQuery[0].totalCount
);
console.log('\n', clientsWithRawQuery)
}
The output is
Using normal client query with groupBy
[
{ _count: 2, country: 'Canada' },
{ _count: 2, country: 'Germany' },
{ _count: 2, country: 'USA' }
]
Using queryRaw
[
{ Country: 'Canada', totalCount: 2n },
{ Country: 'Germany', totalCount: 2n },
{ Country: 'USA', totalCount: 2n }
]
Before Conversion: Typeof Count: bigint
After Conversion: Typeof Count: number
[
{ Country: 'Canada', totalCount: 2 },
{ Country: 'Germany', totalCount: 2 },
{ Country: 'USA', totalCount: 2 }
]

Prisma 2 - Unkown arg 'where' in select.fruit.where for type UserFruit. Did you mean 'select'? Available args

Trying to query in prisma and filter results from a related object but get the error:
Unknown arg 'where' in select.fruit.where for type UserFruit. Did you
mean 'select'? Available args fruit{}
async findShops(req) {
const userId = parseInt(req.params.id);
const shop = await prisma.shop.findMany({
select: {
id: true,
name: true,
logo: true,
fruit:{
select:{
id:true,
userId:true,
fruitNumber:true,
created: true,
updated: true,
},
where: {
userId: userId
}
}
}
})
return shop;
};
example payload expected:
[
{ id: 1001, name: 'test1', logo: 'log.png', fruit: null },
{ id: 1002, name: 'test2', logo: 'log2.jpg', fruit: null },
{ id: 1003, name: 'test3', logo: 'log3.jpg', fruit: null },
{
id: 1005,
name: 'test4',
logo: 'log4.png',
fruit: {
id: '62450ee5-e75d-4a67-8d79-120d11ddf508',
userId: 111,
fruitNumber: '123456',
created: 2022-07-01T06:39:52.924Z,
updated: 2022-07-01T06:39:52.936Z
}
},
{
id: 1004,
name: 'test5',
logo: 'log5.jpg',
fruit: {
id: '20e9af37-2e6f-4070-8475-c5a914f311dc',
userId: 111,
fruitNumber: '123878',
created: 2022-07-01T07:21:27.898Z,
updated: 2022-07-01T07:21:27.901Z
}
}
]
I can easily achieve the expected output by not having the "where" but I need it because the fruit object can contain more than 1 object so I need to filter by userId e.g.
fruit: {
id: '62450ee5-e75d-4a67-8d79-120d11ddf508',
userId: 111,
fruitNumber: '123456',
created: 2022-07-01T06:39:52.924Z,
updated: 2022-07-01T06:39:52.936Z
},
{
id: '62450ee5-e75d-4a67-8d79-120d11ddf508',
userId: 999,
fruitNumber: '123456',
created: 2022-07-01T06:39:52.924Z,
updated: 2022-07-01T06:39:52.936Z
}
For the fruit object I need nulls and anything that matches the userId and based on design it should only ever be 1 record for each shop for the specific user.
At somepoint my code seemed to work but after I did a prisma generate it stopped working. Is there another way I can achieve the same result or is there someway to fix this?
Note:version info below.
model UserFruit {
id String #id #default(uuid())
fruitNumber String #map("fruit_number")
shopId Int #unique #map("shop_id")
userId Int #map("user_id")
created DateTime #default(now())
updated DateTime #updatedAt
fruit Fruit #relation(fields: [fruitId], references: [id])
##unique([userId, fruitId], name: "userFruit")
##map("user_Fruit")
}
model Shop {
id Int #id #default(autoincrement())
name String #unique
logo String
created DateTime #default(now())
updated DateTime #updatedAt
fruit UserFruit?
##map("Shop")
}
model User {
id Int #id #default(autoincrement())
created DateTime #default(now())
updated DateTime #updatedAt
uid String #unique
email String #unique
phone String #unique
firstName String #map("first_name")
lastName String #map("last_name")
dob DateTime?
gender String?
roleId Int #default(1) #map("role_id")
role Role #relation(fields: [roleId], references: [id])
##map("user")
}
Why not do a nested where at the top level to only search for shops whose fruit has the userId you need, rather than doing a nested select? It should make your query simpler and also solve your problem.
const userId = parseInt(req.params.id);
const shop = await prisma.shop.findMany({
select: {
id: true,
name: true,
logo: true,
fruit: {
select: {
id: true,
userId: true,
fruitNumber: true,
created: true,
updated: true,
},
// Removed the nested "where" from here
},
},
where: {
// One of the following conditions must be true
OR: [
// Return shops who have a connected fruit AND
// the fruit's "userId" attribute equals the variable "userID"
{
fruit: {
is: {
userId: userId,
// Can also simplify this to the below line if you want
// userId
},
},
},
// Return shops who do not have a connected fruit
// this will be true if "fruitId" is null
// could also write this as {fruit: {is: {}}}
{
fruitId: {
equals: null,
},
},
],
},
});
This query should output an array of shops where the connected fruit model's userId property equals your userId variable.

error in sequelize > "name": "SequelizeEagerLoadingError"

I have two tables:
//User.js
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define("User", {
userId: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
primaryKey: true,
},
email: {
type: DataTypes.STRING,
},
firstName: {
type: DataTypes.STRING,
allowNull: false,
},
lastName: {
type: DataTypes.STRING,
defaultValue: "",
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
chapterId: {
type: DataTypes.STRING,
},
});
User.associate = (models) => {
User.belongsTo(models.Chapter, {
foreignKey: "chapterId",
targetKey: "chapterId",
as: "chapter",
});
};
return User;
};
and
//chapter table
module.exports = (sequelize, DataTypes) => {
const Chapter = sequelize.define("Chapter", {
chapterId: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
primaryKey: true,
},
chapterName: {
type: DataTypes.STRING,
allowNull: false,
},
isChapterLocal: {
type: DataTypes.BOOLEAN,
allowNull: false,
},
});
Chapter.associate = (models) => {
};
return Chapter;
};
and i am trying to fetch users with chapters included into it.
let getAll = async (req, res) => {
try {
const userData = await db.User.findAll({
include: [
{
model: Chapter,
as: "chapter",
},
],
});
res.send(userData);
} catch (e) {
res.send(e);
}
};
how to include chapter id and chapter name from chapter table, as present in chapterId row for user table.
I am new to sequelize and MySQL and am unsure if the relation i have defined in the user model is good.
Do we need to define associations in both tables.
It should work as expected. E.g.
import { sequelize } from '../../db';
import { Model, DataTypes } from 'sequelize';
class User extends Model {}
User.init(
{
userId: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
primaryKey: true,
},
email: {
type: DataTypes.STRING,
},
firstName: {
type: DataTypes.STRING,
allowNull: false,
},
lastName: {
type: DataTypes.STRING,
defaultValue: '',
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
chapterId: {
type: DataTypes.STRING,
},
},
{ sequelize, modelName: 'User' },
);
class Chapter extends Model {}
Chapter.init(
{
chapterId: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
primaryKey: true,
},
chapterName: {
type: DataTypes.STRING,
allowNull: false,
},
isChapterLocal: {
type: DataTypes.BOOLEAN,
allowNull: false,
},
},
{ sequelize, modelName: 'Chapter' },
);
User.belongsTo(Chapter, { foreignKey: 'chapterId', targetKey: 'chapterId', as: 'chapter' });
(async function test() {
try {
await sequelize.sync({ force: true });
// seed
await User.create(
{
userId: '1',
email: 'example#gmail.com',
firstName: 'Lin',
lastName: 'Du',
password: '123',
chapter: {
chapterId: '1',
chapterName: 'ok',
isChapterLocal: false,
},
},
{ include: [{ model: Chapter, as: 'chapter' }] },
);
// test
const userData = await User.findAll({
include: [{ model: Chapter, as: 'chapter' }],
raw: true,
});
console.log('userData:', userData);
} catch (error) {
console.log(error);
} finally {
sequelize.close();
}
})();
The execution results:
Executing (default): DROP TABLE IF EXISTS "User" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Chapter" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Chapter" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "Chapter" ("chapterId" VARCHAR(255) NOT NULL UNIQUE , "chapterName" VARCHAR(255) NOT NULL, "isChapterLocal" BOOLEAN NOT NULL, PRIMARY KEY ("chapterId"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'Chapter' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS "User" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "User" ("userId" VARCHAR(255) NOT NULL UNIQUE , "email" VARCHAR(255), "firstName" VARCHAR(255) NOT NULL, "lastName" VARCHAR(255) DEFAULT '', "password" VARCHAR(255) NOT NULL, "chapterId" VARCHAR(255) REFERENCES "Chapter" ("chapterId") ON DELETE NO ACTION ON UPDATE CASCADE, PRIMARY KEY ("userId"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'User' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO "Chapter" ("chapterId","chapterName","isChapterLocal") VALUES ($1,$2,$3) RETURNING *;
Executing (default): INSERT INTO "User" ("userId","email","firstName","lastName","password","chapterId") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;
Executing (default): SELECT "User"."userId", "User"."email", "User"."firstName", "User"."lastName", "User"."password", "User"."chapterId", "chapter"."chapterId" AS "chapter.chapterId", "chapter"."chapterName" AS "chapter.chapterName", "chapter"."isChapterLocal" AS "chapter.isChapterLocal" FROM "User" AS "User" LEFT OUTER JOIN "Chapter" AS "chapter" ON "User"."chapterId" = "chapter"."chapterId";
userData: [ { userId: '1',
email: 'example#gmail.com',
firstName: 'Lin',
lastName: 'Du',
password: '123',
chapterId: '1',
'chapter.chapterId': '1',
'chapter.chapterName': 'ok',
'chapter.isChapterLocal': false } ]
Check the database:
node-sequelize-examples=# select * from "User";
userId | email | firstName | lastName | password | chapterId
--------+-------------------+-----------+----------+----------+-----------
1 | example#gmail.com | Lin | Du | 123 | 1
(1 row)
node-sequelize-examples=# select * from "Chapter";
chapterId | chapterName | isChapterLocal
-----------+-------------+----------------
1 | ok | f
(1 row)