use knex to dynamically create join table - javascript

I'm learning knex right now and trying to dynamically insert the id numbers from two different tables into the empty table that will be used as a join table later on.
This is what I have so far, but I feel I'm way off base at the moment.
exports.seed = function(knex, Promise) {
return knex('future_join_table').del()
.then(function () {
return Promise.all([
// Inserts seed entries
knex('future_join_table').insert({
first_id: knex('table1').select('id'),
second_id: knex('table2').select('id')
})
]);
});
};

exports.seed = (knex) => {
let table1Array = [];
const toBeInsertRows = []
return knex('future_join_table').del()
.then(() => knex.select('id').from('table1'))
.then((rows) => {
table1Array = rows;
return knex.select('id').from('table2')
})
.then((rows) => {
rows.forEach((row, index) => toBeInsertRows.push({ first_id: table1Array[index].id, second_id: row.id }))
return knex('future_join_table').insert(toBeInsertRows);
});
}
The code above assume your table1 and table2 have same number of item.
I don't know why would you make a middle table in this way, but so far we can't perform any join operation base on your information.

Related

How to get specific object item from array of objects

I'm having this map function to map through some table data.
const Rows = dataToFilter.children.map((row: any) => {
return row.table_row;
});
console.log("ROWSSS", Rows);
...and as a result i'm getting this complex array of objects:
How can i get the two columns of arrays highlited?
Don't have the data to test, but this could be a possibility
const Rows = dataToFilter.children.map((row: any) => {
const [colOne, colTwo] = row.table_row.cells;
return {
colOne,
colTwo
}
});
You can try this:
const Rows = dataToFilter.children.map((row: any) => {
return [row.table_row.cells[0], row.table_row.cells[1]];
});
console.log("ROWSSS", Rows);

only one object being set to app.set() Expressjs

Good Afternoon,
I am using the MERN stack to making a simple invoice application.
I have a function that runs 2 forEach() that goes through the invoices in the DB and the Users. if the emails match then it gives the invoices for that user.
When I log DBElement to the console it works, it has the proper data, but when I log test1 to the console (app.get()) it only has one object not both.
// forEach() function
function matchUserAndInvoice(dbInvoices, dbUsers) {
dbInvoices.forEach((DBElement) => {
dbUsers.forEach((userElement) => {
if(DBElement.customer_email === userElement.email){
const arrayNew = [DBElement];
arrayNew.push(DBElement);
app.set('test', arrayNew);
}
})
})
}
// end point that triggers the function and uses the data.
app.get('/test', async (req,res) => {
const invoices = app.get('Invoices');
const users = await fetchUsersFromDB().catch((e) => {console.log(e)});
matchUserAndInvoice(invoices,users,res);
const test1 = await app.get('test');
console.log(test1);
res.json(test1);
})
function matchUserAndInvoice(dbInvoices, dbUsers) {
let newArray = [];
dbInvoices.forEach((DBElement) => {
dbUsers.forEach(async(userElement) => {
if(DBElement.customer_email === userElement.email){
newArray.push(DBElement);
app.set('test', newArray);
}
})
})
}
app.set('test', DBElement); overrides the existing DBElement, so only the last matching DBElement is shown in test1.
If you want to have test correspond to all matching DBElement, you should set it to an array, and then append a new DBElement to the array each time it matches inside the for-loop:
if(DBElement.customer_email === userElement.email){
let newArray = await app.get('test');
newArray.push(DBElement);
app.set('test', newArray);
}

Sequelize query SELECT * FROM Table only returning one row

I'm currently using PostgreSQL and Sequelize.js to query some data. When I'm using sequelize.query(), it only returns one row data but when I enter it through pgAdmin it works as expected.
Here is the code I use in sequelize.query().
SELECT table2.student_id,
s.canvasser_name,
l.level_name,
table2.total_score
FROM (SELECT table1.student_id,
sum(table1.max_score) total_score
FROM (SELECT sq.student_id,
max(sq.score) max_score
FROM public.student_quiz sq
GROUP BY sq.quiz_id, sq.student_id) table1
GROUP BY table1.student_id) table2
INNER JOIN public.student s
ON s.id = table2.student_id
INNER JOIN public.level l
ON l.id = s.level_id
ORDER BY table2.total_score DESC
LIMIT 10;
And here is the nodejs code
const getRank = (option, logs = {}) => new Promise(async (resolve, reject) => {
try {
let { offset, limit } = option;
if (!limit) limit = 10;
const result = await sequelize.query(
`SELECT table2.student_id,
s.canvasser_name,
l.level_name,
table2.total_score
FROM (SELECT table1.student_id,
sum(table1.max_score) total_score
FROM (SELECT sq.student_id,
max(sq.score) max_score
FROM public.student_quiz sq
GROUP BY sq.quiz_id, sq.student_id) table1
GROUP BY table1.student_id) table2
INNER JOIN public.student s
ON s.id = table2.student_id
INNER JOIN public.level l
ON l.id = s.level_id
ORDER BY table2.total_score DESC
LIMIT 10;`,
{ plain: true }
);
return resolve(result);
} catch (error) {
let customErr = error;
if (!error.code) customErr = Helpers.customErrCode(error, null, undefinedError);
logger.error(logs);
return reject(customErr);
}
});
And here is the code that consume the function above
const getRankController = async (req, res) => {
try {
const { offset, limit } = req.query;
const result = await getRank({ offset, limit });
if (result.length < 1) {
return Helpers.response(res, {
success: false,
message: 'cannot get score list'
}, 404);
}
return Helpers.response(res, {
success: true,
result
});
} catch (error) {
return Helpers.error(res, error);
}
};
In the meantime, I'm trying another approach using the sequelize built in function, here is the code.
const getRank = (
option,
logs = {}
) => new Promise(async (resolve, reject) => {
try {
// eslint-disable-next-line prefer-const
let { offset, limit } = option;
if (!limit) limit = 10;
const result2 = await StudentQuiz.findAll({
attributes: ['studentId', [sequelize.fn('sum', sequelize.fn('max', sequelize.col('score'))), 'totalPrice'], 'quizId'],
group: 'studentId',
include: [
{
model: Student,
include: [{
model: Level
}],
},
],
offset,
limit
});
return resolve(result2);
} catch (error) {
let customErr = error;
if (!error.code) customErr = Helpers.customErrCode(error, null, undefinedError);
logger.error(logs);
return reject(customErr);
}
});
This one does not work since it is nested function, I kinda don't get it how to reproduce it.
I've tried to do some simple query like SELECT * FROM table and it returns one row, and then I've found out that I need to add "public" to table name so it became SELECT * FROM public.table and it works out. Well, until I'm trying the code in the second code block.
Any answer or advice will be appreciated, thank you.
I suppose you need to indicate a query type and remove plain: true option like this:
const result = await sequelize.query(
`SELECT table2.student_id,
s.canvasser_name,
l.level_name,
table2.total_score
FROM (SELECT table1.student_id,
sum(table1.max_score) total_score
FROM (SELECT sq.student_id,
max(sq.score) max_score
FROM public.student_quiz sq
GROUP BY sq.quiz_id, sq.student_id) table1
GROUP BY table1.student_id) table2
INNER JOIN public.student s
ON s.id = table2.student_id
INNER JOIN public.level l
ON l.id = s.level_id
ORDER BY table2.total_score DESC
LIMIT 10;`,
{
type: Sequelize.QueryTypes.SELECT
}
);
From Sequelize documentation:
options.plain - Sets the query type to SELECT and return a single row

Protractor - How to use multi filters to find out the target row

I want to filter out the target row which contains the specific text in the cell of cells belong to this row.
Here is my code:
private selectTargetLicense(licenseName: string) {
return new Promise((resolve => {
element.all(by.tagName('clr-dg-table-wrapper')).first().all(by.tagName('clr-dg-row')).filter(function (row_element) {
return row_element.all(by.tagName('clr-dg-cell')).filter(function (cell) {
return cell.getWebElement().getText().then(function (text) {
return text.trim() === licenseName;
})
})
}).first().getWebElement().click().then(() => {
resolve();
})
}))
}
It not works as what I think that failed to get the target row from the rows in the table.
So how should I use the multi filter correctly?
Thanks.
It's quite hard to investigate your code without HTML code. Could you show it us?
Do you want to click a cell with given text or entire row?
Code for clicking the cell:
private selectTargetLicense(licenseName: string) {
const rows = element.all(by.css('clr-dg-table-wrapper:nth-of-type(1) clr-dg-row clr-dg-cell'));
return rows.filter((row_element) => {
return row_element.getText().then((text) => {
return text.trim() === licenseName;
});
}).first().click();
}
No need to use nested filter, filter on rows is sufficient.
private selectTargetLicense(licenseName: string) {
const rows = element(by.css('clr-dg-table-wrapper')).all(by.css('clr-dg-row'));
rows.filter((row) => {
// read text of all cells of one row into array: txts
return row.all(by.css('clr-dg-cell')).getText().then((txts) => {
return txts.map((it)=>{
// trim each text
return it.trim();
})
// use array.includes() to detect row contains specified licenseName
.includes(licenseName);
});
})
.first()
.click();
}

How to filter out items that were not previously added to an array in React Native?

Whenever a user does a product search in our app we need to cache the search results in local storage so that when they are offline and they perform a search it can pull up previously searched items. With each new search we need to only add the new items to the searchCache. So if they search for 'be' first then search for 'b' there will be overlapping results but we don't want to add items that are already stored. This is currently not working though because it still returns all of the items in the search instead of filtering them. Does anyone know how to achieve this?
I want to filter the searchResults by their ids. Comparing ids to return the items that have ids that are not already in the searchCache.
newItems = searchResults.filter((searchResult) => {
return searchCache.find(searchCacheItem => searchCacheItem.id !== searchResult.id);
});
Here is the entire action function:
export function handleProductSearch(searchTerm) {
return (dispatch, getState) => {
return dispatch(getProductList(searchTerm)).then((results) => {
const searchResults = results.items;
// Get previously stored product search cache
AsyncStorage.getItem(STORAGE_KEY_PRODUCT_SEARCH_CACHE).then((results) => {
return JSON.parse(results);
}).then((response) => {
const searchCache = response || [];
let newItems = [];
if (searchCache.length > 0) {
// Check for duplicates in the recently added items. Only add the items that are new and not already in the searchCache.
newItems = searchResults.filter((searchResult) => {
return searchCache.find(searchCacheItem => searchCacheItem.id !== searchResult.id);
});
}
searchCache.push(newItems.length > 0 ? newItems : searchResults);
AsyncStorage.setItem(STORAGE_KEY_PRODUCT_SEARCH_CACHE, JSON.stringify(searchCache));
}).catch(err => {
console.log('Error retrieving product search cache: ', err);
});
});
};
}
You should first check if the item is already exists and then if not push it to the array.
Sample
let newItems = [];
if (searchCache.length > 0) {
// Check for duplicates in the recently added items. Only add the items that are new and not already in the searchCache.
searchResults.forEach(searchResultItem => {
if(!searchCache.find(searchCacheItem => searchCacheItem.id === searchResultItem.id)) newItems.push(item)
});
}

Categories