I have skills in one table, user_skills in other table and getting skills against id from skills table in for loop.I have stored query results in javascript array. I want a array with objects in it. I'm getting array in array structure. As you can see in image that i am getting multiple arrays in array.It should be objects in single array.
var userExist = await ctx.app.pool.query("SELECT * FROM USER_SKILLS WHERE user_id = $1",
[`${user_id}`]);
var strArray = userExist.rows[0].skill_array.split(",");
var i;
var skillsArray = [];
for (i = 0; i < strArray.length; i++) {
var findSkill = await ctx.app.pool.query("SELECT skill_name FROM ALL_SKILLS WHERE id = $1",
[`${strArray[i]}`]);
skillsArray.push(findSkill.rows);
}
console.log('skillsArray', skillsArray);
ctx.body = {
status: 200,
error: false,
message: "Skills found",
data: skillsArray
};
Assuming skill_array is in fact an array in postgres, you can combine both those queries into one:
const query = "SELECT skill_name
FROM ALL_SKILLS
WHERE id = ANY((
SELECT skill_array
FROM USER_SKILLS
WHERE user_id = $1
))";
const res = await ctx.app.pool.query(query, [`${user_id}`]);
That will be more performant than doing multiple queries.
Then the reason why you're getting an array with arrays is because skillsArray.push(findSkill.rows) puts the whole rows property, which is an array, into your skillsArray array.
It's not entirely clear to me exactly what is the format of the result you want, but I'll assume it's the actual skill names in an array, something like:
{
message: "Skills found",
data: [
"PHP",
"Node js"
]
}
In which case you could restructure your code to be something like this:
const query = "SELECT STRING_AGG(skill_name, ',') AS skill_names
FROM ALL_SKILLS
WHERE id = ANY((
SELECT skill_array
FROM USER_SKILLS
WHERE user_id = $1
))";
const res = await ctx.app.pool.query(query, [`${user_id}`]);
const skillNames = res.rows[0].skill_names.split(',');
ctx.body = {
status: 200,
error: false,
message: "Skills found",
data: skillNames
};
I've added a STRING_AGG because I like to get postgres results in a single row if possible rather than have pg read multiple rows sequentially, I believe it will be faster. I'm not using ARRAY_AGG because I don't know how the pg module treats arrays, whether it converts them to string or a js array. So I return one field with the skills concatenated with a comma, e.g. "PHP,Node js", then just need to split that one field by the comma to get the desired array.
I believe this is what you want
var userExist = await ctx.app.pool.query("SELECT * FROM USER_SKILLS WHERE user_id = $1",
[`${user_id}`]);
var strArray = userExist.rows[0].skill_array.split(",");
var i;
var skillsArray = [];
for (i = 0; i < strArray.length; i++) {
var findSkill = await ctx.app.pool.query("SELECT skill_name FROM ALL_SKILLS WHERE id = $1",
[`${strArray[i]}`]);
skillsArray.push(findSkill.rows[0]);
}
console.log('skillsArray', skillsArray);
ctx.body = {
status: 200,
error: false,
message: "Skills found",
data: skillsArray
};
But I as i mentioned in my comment, I suggest that you have your database tables/schema in relationships M:M, in your case, where you can just get the data you need in a single query, and it is considered bad practice to do a query in for(...) loop like this. you should use ORM like Sequelize or any other ORM that you prefer and works well with KOA, I hope this help you in achieving this:
Related
I have a stripe function where I am trying to push the images into the array for each product. This is part of the prebuilt stripe checkout page... here's my function at whole:
//defining arrays
var productsArray = [];
var priceArray = [];
var imageArray = [];
//query to database
var productsStripe = "select * from " + tableID + "";
ibmdb.open(db2ConnString, function(err, conn) {
if (err) return console.log(err);
conn.query(productsStripe, async function (err, rows) {
if (err) {
console.log(err)
}
console.log(rows)
var itemName = ""
var itemPrice = ""
var totalNewPriceTest = ""
for(var i = 0; i < rows.length; i++)
//inserting items and prices into arrays
productsArray.push(rows[i]['NAME'])
priceArray.push(rows[i]['PRICE'])
imageArray.push(rows[i]['IMAGE_URL'])
}
//stripe
// loop over products array to construct the line_items
const items = productsArray.map((product, i) => {
return {
price_data: {
currency: 'CAD',
product_data: {
name: product,
images: imageArray[i]
},
unit_amount: parseInt(priceArray[i], 10) * 100,
},
quantity: 1,
};
});
its returning the error: (node:39728) UnhandledPromiseRejectionWarning: Error: Invalid array
how do I get the image array to populate the stripe page with images too? I pushed the values into the array, and am calling them , but not sure why it is returning invalid array. any ideas?
Observations
imageArray is array containing image urls for different products, one for each product in the productArray.
From the name of the prop images, the error message and the error line info provided by the OP, the prop images ought to be an array.
In the code, image: imageArray[i] means that the image prop is assigned a string but it should be array. So changing it with [imageArray[i]], we are assigning an array of length one to image prop containing image url for that product.
I have a cypress test which has been set up with mysql node module. When I run bellow mentioned test Its giving output as follows.
const executeQuery = (query) => {
cy.task('DBQuery', query).then(function (recordset) {
var rec = recordset
cy.log(rec)
})
}
Query:
select *
from Users
where email = 'sheeranlymited#lymitedtest.com'
OUTPUT: log [Object{23}]
Query:
select firstname
from Users
where email = 'sheeranlymited#lymitedtest.com'
OUTPUT: log [{firstname: Edward}]
instead of cy.log(rec) I want to get the output of 23 columns to assign in to different variables based on the column name.
Appreciate if someone can help me to resolve this...
You can use Object.values in js to retrieve values from your object
Let's say you need to extract the value of the 3rd column, so your code will look like,
cy.task('DBQuery', query).then(function (recordset) {
var rec = recordset
const results = Object.values(rec[0])
// results[index of the column] will output the results
cy.log(results[3])
})
We can do a small modification to make your task easier,
cy.task('DBQuery', query).then(function (recordset) {
var rec = recordset
const Values = Object.values(rec[0]);
const keys = Object.keys(rec[0]);
let result = {};
let index = 0;
keys.forEach(key => {
result[keys[index]] = Values[index];
i++
})
//result.firstName will give you your results
cy.log(result.firstName);
})
In this way, we are generating key-value pairs having the key as the column name. So you can use the column name to find the value.
Hope this helps.
cheers.
Can this be done as one query so there is not multiple request to the DB with the loop? Im trying to get each cameras last photo if any.
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
let cameras = await knex({ cameras: "device_manager_camera" })
.select()
.where("owner_id", 13);
const start = async () => {
let report = [];
asyncForEach(cameras, async camera => {
let photo = await knex({ photos: "device_manager_photo" })
.where("camera_id", camera.id)
.first();
if (photo) {
report[camera.name] = photo.timestamp;
} else {
report[camera.name] = "never";
}
});
console.log(report);
};
start();
First of all, I'd recommend you to write your SQL query in plain SQL and it would be much easier to translate it to knex commands.
As for your request, I've come up with this query which returns the array of [{ camera_id, timestamp }]. It selects cameras of the owner with id 13 and joins this to max timestamps grouped query from table photos.
select
c.name,
coalesce(t.timestamp::text, 'never') as timestamp
from
cameras as c
left join (
select
p.camera_id,
max(p.timestamp) as timestamp
from
photos as p
group by
camera_id
) as t on t.camera_id = c.id
where
c.owner_id = 13;
Correct your table names and columns if necessary.
Bonus style points. I'd not recommend using timestamp as a column name. It is a reserved column in some databases and it might need quotes around it to explicitly specify it as a column in your query, which might be annoying.
I have pouchdb/couchbase data with equipment that has user assigned to them.
Equipment with _id and in the equipment doc there is a checkedOutBy with the user._id as the value. Within the employee object there is user.name. When I get the equipment objects how do I also get the user.name and display with the equipment.
I have searched and read about map/reduce that uses emit and do not grasp the idea. My code that i wrote from what i learned is:
by the way I am also using Angularjs.
field = "eq::"
this.getAllEquip = function(field){
function map(doc) {
if (doc.checkedOutBy !== undefined) {
emit(doc.checkedOutBy, {empName : doc.name});
}
}
var result = database.query(map, {include_docs: true,
attachments: true,
startkey: field,
endkey: field + '\uffff'})
.catch(function (err) {
//error stuff here
});
return result
};
I don't see where the two docs would get together. What am i missing? My result is empty.
The equipment json looks like:
{checkedOutBy: "us::10015", description: "3P Microsoft Surface w/stylus & power cord", equipId: "SUR1501", purchaseDate: "", rCost: 1000, id:"eq::10001"}
Emlpoyee json:
{"firstname":"Joe","gender":"male","lastname":"Blow","status":"active","title":"office","type":"userInfo","_id":"us::10015","_rev":"2-95e9f34784094104ad24bbf2894ae786"}
Thank you for your help.
Something like this should work, if I understood the question correctly:
//Sample Array of Objects with Equipment
var arr1=[{checkedout:"abc1",desc:"item1",id:1},
{checkedout:"abc2",desc:"item2",id:2},
{checkedout:"abc3",desc:"item3",id:3},
{checkedout:"abc1",desc:"item1",id:4},
{checkedout:"abc4",desc:"item3",id:5},
{checkedout:"abc6",desc:"item3",id:6}];
//Sample array of objects with Employee - the "id" in arr2 matches with "checkout" in arr1
var arr2=[{name:"john",id:"abc1"},
{name:"jack",id:"abc2"},
{name:"alice",id:"abc3"},
{name:"james",id:"abc4"}];
var result = []; //final result array
//loop through equipment array arr1
arr1.forEach(function(obj) {
var tempObj = obj;
var checkedout_id=obj.checkedout;
//do array.find which will return the first element in the array which satisfies the given function. This is absed on the assumption that that the id is unique for employee and there wont bwe multiple employees with same id (which is the "checkedout" field in equipment. If the employee is not found, it will return undefined.
var foundname = arr2.find(function(obj) {
if (obj.id == checkedout_id)
return obj.name
})
//Create the object to be inserted into the final array by adding a new key called "name", based on the result of above find function
if (foundname != undefined) {
tempObj.name=foundname.name
}
else {
tempObj.name = "Not found";
}
result.push(tempObj);
})
This is my Pouchdb solution, thank you Vijay for leading me to this solution.
First I get all my equipment. Then I use Vijay's idea to loop through the array and add the name to the object and build new array. I found there is a need to go into the .doc. part of the object as in obj.doc.checkedOutBy and tempObj.doc.name to get the job done.
$pouchDB.getAllDocs('eq::').then(function(udata){
var result = [];
//loop through equipment array
udata.rows.forEach(function(obj) {
var tempObj = obj;
var checkedout_id=obj.doc.checkedOutBy;
if (checkedout_id != undefined) {
$pouchDB.get(checkedout_id).then(function(emp){
return emp.firstname + " " + emp.lastname
}).then(function(name){
tempObj.doc.name = name;
});
}
result.push(tempObj);
})
in my service I have:
this.get = function(documentId) {
return database.get(documentId);
};
and:
this.getAllDocs = function(field){
return database.allDocs({
include_docs: true,
attachments: true,
startkey: field,
endkey: field + '\uffff'});
};
var usersRows = [];
connection.query('SELECT * from users', function(err, rows, fields) {
if (!err) {
rows.forEach(function(row) {
usersRows.push(row);
});
console.log(usersRows);
}
else {
console.log('Error while performing Query.' + err);
}
});
It returned to me:
var usersRows = [ [ RowDataPacket { id: 1, name: 'sall brwon', number: '+99999999\r\n' } ] ];
I need to parse this and remove rowdatapacket; I need result like this:
userRows = { id: 1, name: 'my name is', number: '+999999\r\n' };
If you need to get rid of RowDataPacket's array and save it in yours you can also use this:
usersRows = JSON.parse(JSON.stringify(results));
Have you tried
userRows = RowDataPacket;
You might want to try JSON.stringify(rows)
Was unable to understand and implement the accepted the answer.
Hence, tried the long way out according the results I was getting.
Am using "mysql": "2.13.0" and saw that the this library returned array of array out of which:
Index 0 had array of RowDataPackets
Index 1 had other mysql related information.
Please find the code below:
var userDataList = [];
//Get only the rowdatapackets array which is at position 0
var usersRows = data[0];
//Loop around the data and parse as required
for (var i = 0; i < usersRows.length; i++) {
var userData = {};
//Parse the data if required else just
userData.name = userRows.firstName + userRows.lastName;
userDataList.push(userData);
}
If no parsing is required and you just want the data as is, you could use the solution like mentioned in link How do I loop through or enumerate a JavaScript object?
Have not tried it but could be tweaked and worked out.
There should be simpler way to do it but as a novice I found the above way server the purpose. Do comment in case of better solution.
RowDataPacket is the class name of the object that contains the fields.
The console.log() result [ [ RowDataPacket { id: 1, name: 'sall brwon', number: '+99999999\r\n' } ] ] should be read as "an array of one item, containing and array of one item, containing an object of class RowDataPacket with fields id, name, and number"