How to return nested JSON in node js - mysql

I have three different tables.
1. Order details (id, itemId,date,userId)
2. Item details (id, itemName, quantity)
3. User details (id, userName)
I want to return a JSON as:
{[
{
orderId = 1,
items = [
{
itemId = 1,
itemName = ITEM_DEMO,
},
{
itemId = 2,
itemName = ITEM_DEMO2,
}
],
userDetails = {
userId = 1,
userName = TEST_USER
}
}
]}
How can we do this in Node JS. Im using MySQL.

First of all you should read about object and json in javascript.
For parsing your data from mySql to json do the following steps:
Create an object that is filled with your data from mySql.
const ArrayObjectFilledWithMysqlData = [
{
orderId: 1,
items: [{
itemId: 1,
itemName: ITEM_DEMO,
},
{
itemId: 2,
itemName: ITEM_DEMO2,
}]
},
{
userDetails: {
userId: 1,
userName: TEST_USER
}
}
]
Parse the Array to json.
const jsonFromData = JSON.stringify(ArrayObjectFilledWithMysqlData)

Related

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.

how to group data entries with same id into a single entry?

I am a beginner in MySQL as well as Typeorm. So my query returns data with the same ID like:
[
{
id: "1",
name: "john",
place: "San Francisco"
},
{
id: "1",
name: "john",
place: "Mumbai"
}
]
Now I want data where there is an entry with a unique id, let's say:
[
{
id: "1",
name: "john",
place: ["San Francisco", "Mumbai"]
}
]
can someone help me, how do I groupBy to achieve this result?
I doubt that you can get an array, but you could use group_concat.
https://mariadb.com/kb/en/group_concat/
The query would be something like
SELECT `id`, group_concat(`name`), group_concat(`place`) FROM <table_name> GROUP BY `id`
if the name doesn't need to be concatenated
SELECT `id`, `name`, group_concat(`place`) FROM <table_name> GROUP BY `id`
And then in your code you can split that string in array. Either use ',' which I think it's the default separator or use a custom one like '!#$!'
With MySQL you can use GROUP_CONCAT:
SELECT
id, name, GROUP_CONCAT(place)
FROM
<table_name>
GROUP BY
id
With TypeScript you can use Array.prototype.reduce():
const data = [{id: "1",name: "john",place: "San Francisco"},{id: "1",name: "john",place: "Mumbai"}]
const dataHash = data.reduce((a, { id, name, place }) => {
a[id] = a[id] || { id, name, place: [] }
a[id].place.push(place)
return a
}, {})
const result = Object.values(dataHash)
console.log(result)

Create a dynamic Mysql Insert from an Object

I have a project in Typescript in which I am trying to create an Insert through the options that I send through an object. Right now I have two objects, one for each Insert, these Inserts are created in different tables and with different objects. I would like to know if it is possible to create a general Insert for several objects.
This is what I currently have:
let object1 = [
{ country: 'CO', name: 'CO_SE.xml', exists: 1 },
{ country: 'CO', name: 'CO_IN.xml', exists: 1 },
{ country: 'CO', name: 'CO_BR.xml', exists: 1 }
];
`INSERT INTO ${database} VALUES` + object1.map((elem: any) =>
`"${elem.country}", "${elem.name}", ${elem.exists})`).join(', ');
let object2 = [
{ code: 1, folder: '/ToFtp', max: 8 },
{ code: 2, folder: '/ToXml', max: 5 },
{ code: 3, folder: '/ToMail', max: 5 }
];
`INSERT INTO ${database} VALUES` + object2.map((elem: any) =>
`${elem.code}, "${elem.folder}", ${elem.max})`).join(', ');
This is what I am trying to achieve:
let object1 = [
{ country: 'CO', name: 'CO_SE.xml', exists: 1 },
{ country: 'CO', name: 'CO_IN.xml', exists: 1 },
{ country: 'CO', name: 'CO_BR.xml', exists: 1 }
];
let object2 = [
{ code: 1, folder: '/ToFtp', max: 8 },
{ code: 2, folder: '/ToXml', max: 5 },
{ code: 3, folder: '/ToMail', max: 5 }
];
`INSERT INTO ${database} VALUES` + ${object}.map((elem: any) =>
`"${elem.elem1}", ... ${elem.elemN})`).join(', ');
Is this possible? I'm not sure this can be done.
You can create methods to prepare your query and values. You can do something like this.
let object1 = [
{ country: 'CO', name: 'CO_SE.xml', exists: 1 },
{ country: 'CO', name: 'CO_IN.xml', exists: 1 },
{ country: 'CO', name: 'CO_BR.xml', exists: 1 }
];
function getValues<T extends Record<string, any>[]>(obj: T) {
const values = obj.map((item) => {
const val = Object.values(item).map((v) => v);
return val;
});
return values;
}
function getColumns<T extends Record<string, any>>(obj: T) {
return Object.keys(obj);
}
function getFilters<T extends Record<string, any>>(obj: T) {
const constraints: string[] = [];
const queryArray: any[] = [];
Object.entries(obj).forEach(([k, v]) => {
constraints.push(`${k} = ?`);
queryArray.push(v);
});
return {
constraints,
queryArray
}
}
const columns = getColumns(object1[0]);
const values = getValues(object1);
const sql = `INSERT INTO MyTable(${columns.join(", ")}) VALUES ?`;
const filters = {
country: "CO"
};
const selectFilters = getFilters(filters);
const selectSql = `SELECT ${columns} FROM MyTable WHERE ${selectFilters.constraints.join(" AND ")}`;
console.log(columns); // [ 'country', 'name', 'exists' ]
console.log(sql); // INSERT INTO MyTable(country, name, exists) VALUES ?
console.log(values); // [ [ 'CO', 'CO_SE.xml', 1 ], [ 'CO', 'CO_IN.xml', 1 ], [ 'CO', 'CO_BR.xml', 1 ] ]
// now you can use something like this
connection.query({ sql, values });
Note: Make sure you sanitize your input before using these functions to avoid any damage you may create if your input is not as you are expecting it.

Parsing JSON in Postgres

I have the following JSON that I'd like to parse inside a postgresql function.
{
"people": [
{
"person_name": "Person#1",
"jobs": [
{
"job_title": "Job#1"
},
{
"job_name": "Job#2"
}
]
}
]
}
I need to know how to pull out the person_name, and then loop thru the jobs and pull out the job_title. This is as far as I've been able to get.
select ('{"people":[{"person_name":"Person#1","jobs":[{"job_title":"Job#1"},
{"job_name":"Job#2"}]}]}')::json -> 'people';
https://www.db-fiddle.com/f/vcgya7WtVdvj8q5ck5TqgX/0
Assuming that job_name in your post should be job_title. I expanded your test data to:
{
"people": [{
"person_name": "Person#1",
"jobs": [{
"job_title": "Job#11"
},
{
"job_title": "Job#12"
}]
},
{
"person_name": "Person#2",
"jobs": [{
"job_title": "Job#21"
},
{
"job_title": "Job#22"
},
{
"job_title": "Job#23"
}]
}]
}
Query:
SELECT
person -> 'person_name' as person_name, -- B
json_array_elements(person -> 'jobs') -> 'job_title' as job_title -- C
FROM (
SELECT
json_array_elements(json_data -> 'people') as person -- A
FROM (
SELECT (
'{"people":[ '
|| '{"person_name":"Person#1","jobs":[{"job_title":"Job#11"}, {"job_title":"Job#12"}]}, '
|| '{"person_name":"Person#2","jobs":[{"job_title":"Job#21"}, {"job_title":"Job#22"}, {"job_title":"Job#23"}]} '
|| ']}'
)::json as json_data
)s
)s
A Getting person array; json_array_elements expands all array elements into one row per element
B Getting person_name from array elements
C Expanding the job array elements into one row per element and getting the job_title
Result:
person_name job_title
----------- ---------
"Person#1" "Job#11"
"Person#1" "Job#12"
"Person#2" "Job#21"
"Person#2" "Job#22"
"Person#2" "Job#23"