Sequelize: findAndCountAll(), but with a specific row as the first entry - javascript

I've a table that I'm querying using findAndCountAll()
I'm basically using it for pagination/ordering using the order, limit and index properties. Something simple like this:
exports.getApplications = async(req, res, next) => {
const findOne = req.query.indexId;
const index = req.query.index || 0;
const limit = req.query.limit || 10;
const orderField = req.query.orderField || 'createdAt';
const orderDirection = req.query.orderDirection || 'DESC';
const order = [ orderField, orderDirection ];
const applications = await Application.findAndCountAll({
order: [order],
limit: parseInt(limit, 10),
offset: parseInt(index)
// ...
}
}
But I'd also like to be able to specify a particular indexId (findOne), and have that single entry appear before the paginated/ordered list (*edit: The row may or may not be included in the paginated list that's returned)
Is that possible using findAndCountAll? Or would I have to run a separate query using findByPk(), reduce the limit by 1, then unshift the entry to the front of the results array?
Thanks,
Nick
*Edit - Implementation in case anyone is interested. Now just have to make the queries run in parallel :)
try {
// Find a specific row to highlight if needed
if(findOne) {
topRow = await Application.findByPk(findOne, {
include: [...],
});
}
const applications = await Application.findAndCountAll({
include: [...],
order: [order],
limit: parseInt(limit, 10),
offset: parseInt(index)
});
// If there's a row to be highlighted
if(topRow) {
const visible = applications.rows.filter(application => application.id === topRow.id);
const index = applications.rows.findIndex(application => application.id === topRow.id);
// 1 too many results in the array
if(applications.rows.length + 1 > limit) {
// If the row appears in the array to be returned, remove it
if(visible) {
applications.rows.splice(index, 1);
} else {
// Remove the last element instead
applications.rows.pop();
}
} else {
if(visible) applications.rows.splice(index, 1);
}
// Add the highlighted topRow to the array
applications.rows.unshift(topRow)
}

Try to do this, assuming your findOne value is safe to use:
order: [
[sequelize.literal(`id = ${findOne}`), 'DESC'],
[orderField, orderDirection]
]
This will return true for the row you want, false for others, so it will first sort it to the top, then continue the rest of the ordering.

Related

Use array of invoice numbers to create invoice objects within which each invoice number from the initial array serves as id property

Building a script in google apps script.
I get values from an invoice data sheet with multiple lines per invoice so as to account for line items.
My progress so far has been to extract individual invoice numbers from the column (each invoice number occurs as many line items the individual invoice has).
The array todaysInvoices looks like this: [35033817, 35033818, 35033819, 35033820, 35033821]
Now, I need a way to create an object for each of these invoice numbers that has different properties (such as invoiceDate and customerName etc.). The initial invoice number as in the array should thereby be assigned as 'id' property to the new invoice object.
I need help to use objects in javascript.
If you require additional information, please let me know.
Below is a screenshot of a simplified version of my order sheet:
This is a clipping of my order sheet. Before and after the shown columns there are many more with more details but the hierarchies of information are already in the image
Below is the code I have so far:
const orderSheet = SpreadsheetApp.openById('SPREADSHEETID').getSheetByName('SHEETNAME');
const invoiceTemplate = DriveApp.getFileById('DOCUMENTID');
const tempFolder = DriveApp.getFolderById('FOLDERID');
const invoiceData = orderSheet.getRange(4,7, orderSheet.getLastRow() - 1, 57).getDisplayValues().filter(function (rows){ return rows[0] === 'INVOICED'});
const invDataRepo = SpreadsheetApp.openById('SPREADSHEETID2');
var timestamp = new Date();
function printBulkInvoices() {
logLineItems ();
var todaysInvoices = uniqueInvIDs ();
todaysInvoices.sort();
todaysInvoices.map(String);
//fetchInvData (todaysInvoices);
Logger.log (todaysInvoices)
}
function fetchInvData (invoiceIDs) {
let invoices = {
}
Logger.log(invoices)
invoiceIDs.forEach
}
function fetchLineItems (invoiceDataArray) {
}
// send array of todays unique invoice numbers (later all inv data?) to invdata sheet and log them
function logTodaysInvoices (invIDArr){
invIDArr.forEach
invDataRepo.getSheetByName('invdata').getRange(invDataRepo.getSheetByName('invdata').getLastRow()+1,1,invIDArr.length,1).setValue(invIDArr);
}
// return an array of unique invoice ids from todays invoice data
function uniqueInvIDs (){
let singleArray = invoiceData.map(row => row[5]);
let unique = [...new Set(singleArray)];
return unique;
}
//log incoicedata to invdatarepo-sheet 'lineitems'
function logLineItems (){
invDataRepo.getSheetByName('lineitems').getRange(invDataRepo.getSheetByName('lineitems').getLastRow()+1,2,invoiceData.length,invoiceData[0].length).setValues(invoiceData);
}
It's hard to say exactly what you need since we cannot see your Invoice Data Sheet.
But here's something that might give you a start:
let iobj = {idA:[]};
[35033817, 35033818, 35033819, 35033820, 35033821].forEach((id => {
if(!iobj.hasOwnProperty(id)) {
iobj[id]={date: invoiceDate, name: customName, items:[]};
iobj.idA.push(id);//I find it handy to have an array of object properties to loop through when I wish to reorganize the data after it's all collected
} else {
iobj[id].items.push({item info properties});//I am guessing here that you may wish to addition additional information about the items which are on the current invoice
}
});
Javascript Object
To follow up from your question:
Your loop to collect object data would start to look something like this:
function getInvoiceData() {
const ss = SpreadsheetApp.getActive();
const ish = ss.getSheetByName('Invoice Data');
const isr = 2;
const hA = ish.getRange(1, 1, 1, ish.getLastColumn()).getValues()[0];
let idx = {};//object return head index into row array based on header title which in this case I assume invoice number is labeled 'Invoicenumber'
hA.forEach((h, i) => {idx[h] = i});
const vs = ish.getRange(isr, 1, ish.getLastRow() - isr + 1, ish.getLastColumn()).getValues();
let iobj = { idA: [] };
vs.forEach(r => {
if (!iobj.hasOwnProperty(r[idx['invoicenumber']])) {
iobj[r[idx['invoicenumber']]] = { date: r[idx['invoicedate']], name: r[idx['customername']], items: [] };
iobj.idA.push(r[idx['invoicenumber']]);
} else {
iobj[r[idx['invoicenumber']]].items.push({ iteminfoproperties:'' });
}
});
}

Find the array length and create a custom line of code?

Here is my code:
const json = `{"BTC":{"available":0.00024868,"onOrder":0,"btcValue":0.00024868,"btcTotal":0.00024868},"LTC":{"available":0,"onOrder":0,"btcValue":0,"btcTotal":0},"ETH":{"available":0,"onOrder":0,"btcValue":0,"btcTotal":0},"NEO":{"available":0,"onOrder":0,"btcValue":0,"btcTotal":0},"BNB":{"available":0.08943066,"onOrder":0,"btcValue":0.0004663808919,"btcTotal":0.0004663808919}}`;
const data = JSON.parse(json);
var Table = require('cli-table');
const chalk = require("chalk");
const processed = Object.entries(data)
.filter(([, { available }]) => available > 0)
.map(([asset, { available, btcValue }]) => {
return { asset, available, btcValue };
});
const asArray = processed.map(Object.values);
//console.table(processed);
console.log(asArray);
console.log(asArray.length)
var table = new Table({
head: [chalk.green.bold('Coin'), chalk.green.bold('Available'), chalk.green.bold('BTC Value')]
, colWidths: [25, 25, 25]
});
table.push(
asArray[0], asArray[1]
);
var tableDisplay = table.toString();
console.log(tableDisplay);
I am trying to find a way of finding the asArray length, then putting each index in the table.push no matter how long it is,
So it would list asArray[0], and increase for each index of the array no matter what
the code currently works, but I have to know the length of the array in order to change the code each time.
you can set up a loop to loop through your asArray. A forEach loop will go through each of your element in the array until it reaches the end.
asArrays.forEach( element => {
table.push(element)
})

How to use multiple Nodelists with forEach method

I'm working on a project that is basically a e-store, with a bin. What I'm trying to do is send a POST request to the server with my items from the bin.
I have an empty array. I also have 3 Nodelists, I want to reach their values, textContent, dataset and nest all of them in my empty array.
This is the array:
var products = { Lines: [ ] };
What I've tried so far:
const prName = this.parentNode.parentNode.querySelectorAll('.product-name-link');
const prInput = this.parentNode.parentNode.querySelectorAll('.product-quantity-input');
const prPrice = this.parentNode.parentNode.querySelectorAll('.product-price-total');
prName.forEach(product => products.push(product.dataset.id))
prInput.forEach(product => products.Lines.push(product.value))
prPrice.forEach(product => products.Lines.push(product.textContent))
I want them to have a key=> value like in the example above.
The result that I need to get looks similar to this:
"Lines":[
{
"Assortiment":"1627aea5-8e0a-4371-9022-9b504344e724",
"Quantity":12678967.543233,
"SalePrice":12678967.543233,
"Warehouse":"1627aea5-8e0a-4371-9022-9b504344e724"
},
{
"Assortiment":"1627aea5-8e0a-4371-9022-9b504344e724",
"Quantity":12678967.543233,
"SalePrice":12678967.543233,
"Warehouse":"1627aea5-8e0a-4371-9022-9b504344e724"
},
{
"Assortiment":"1627aea5-8e0a-4371-9022-9b504344e724",
"Quantity":12678967.543233,
"SalePrice":12678967.543233,
"Warehouse":"1627aea5-8e0a-4371-9022-9b504344e724"
}
],
... with everything already said in my comments, a working solution might look like that ...
const products = { Lines: [] };
const prName = this.parentNode.parentNode.querySelectorAll('.product-name-link');
const prInput = this.parentNode.parentNode.querySelectorAll('.product-quantity-input');
const prPrice = this.parentNode.parentNode.querySelectorAll('.product-price-total');
// create a product item with each iteration step ...
prName.forEach((elmNode, idx) => products.Lines.push({
Assortiment: elmNode.dataset.id,
Quantity: prInput.item(idx).value,
SalePrice: prPrice.item(idx).textContent
}));
Wrap them with Array.from() as follows:
Array.from(elements).forEach( function(el) {
console.log(el);
});

JSON Group by Name and then Display Latest Record

Using only JavaScript, I need to
Group by code.
Get latest modifieddate.
Display total grouped code as Count.
Starting JSON Result
[
{"ID":1,"code":"AAA","modifieddate":"2019-06-01","user":"John"},
{"ID":2,"code":"AAA","modifieddate":"2019-06-02","user":"Jane"},
{"ID":3,"code":"AAA","modifieddate":"2019-06-03","user":"Sue"},
{"ID":4,"code":"BBB","modifieddate":"2019-06-10","user":"Rick"},
{"ID":5,"code":"CCC","modifieddate":"2019-06-11","user":"Joe"}
]
Desired JSON Result set
[
{"ID":3,"code":"AAA","modifieddate":"2019-06-03","user":"Sue","Count":"3"},
{"ID":4,"code":"BBB","modifieddate":"2019-06-10","user":"Rick","Count":"1"},
{"ID":5,"code":"CCC","modifieddate":"2019-06-11","user":"Joe","Count":"1"}
]
Tried using reduce method.
I do not have access to modify the server side API code.
I am using Aurelia JS.
You can use Array.reduce to group the result set by each item's code property, incrementing Count as needed, then take the values from the accumulation object. Along the way, we perform a date comparison to determine which the most recent entry to include in the result.
const data = [ {"ID":1,"code":"AAA","modifieddate":"2019-06-01","user":"John"}, {"ID":2,"code":"AAA","modifieddate":"2019-06-02","user":"Jane"}, {"ID":3,"code":"AAA","modifieddate":"2019-06-03","user":"Sue"}, {"ID":4,"code":"BBB","modifieddate":"2019-06-10","user":"Rick"}, {"ID":5,"code":"CCC","modifieddate":"2019-06-11","user":"Joe"} ];
const result = Object.values(data.reduce((a, e) => {
if (!a[e.code]) {
a[e.code] = {...e, Count: 0};
}
if (Date.parse(e.modifieddate) > Date.parse(a[e.code].modifieddate)) {
a[e.code] = {...e, Count: a[e.code].Count};
}
a[e.code].Count++;
return a;
}, {}));
console.log(result);
By the way, this is just a plain JS array we're working with, not JSON.
This should get you:
let array = [
{"ID":1,"code":"AAA","modifieddate":"2019-06-01","user":"John"},
{"ID":2,"code":"AAA","modifieddate":"2019-06-02","user":"Jane"},
{"ID":3,"code":"AAA","modifieddate":"2019-06-03","user":"Sue"},
{"ID":4,"code":"BBB","modifieddate":"2019-06-10","user":"Rick"},
{"ID":5,"code":"CCC","modifieddate":"2019-06-11","user":"Joe"}
]
let result = array.reduce(function(total, currentValue, currentIndex, arr) {
let index = total.findIndex(function(entry) { return entry.code == currentValue.code; })
if (index >= 0) { // entry already exists
// check modified
if (total[index].modifieddate > currentValue.modifieddate) { // already have most recent of the two
total[index].Count += 1;
} else { // need to replace with more recent
currentValue.Count = total[index].Count + 1;
total[index] = currentValue;
}
} else { // first record for this code
currentValue.Count = 1;
total.push(currentValue);
}
return total;
}, []);
console.log(result);
Here is a working js-fiddle
Note: Comments are made in code block

Remove singular element from an object's key array

I have an object that has multiple keys and each of these keys has an array storing multiple elements. I want to be able to remove a specified element from the key's array.
I have tried using the delete keyword as well as the filter method, but I have been unsuccessful. I'm a total newbie to JS so I appreciate any assistance. Also, I want to do this using ONLY JavaScript, no libraries.
Here is the code where I am creating my object:
function add(task, weekdayDue) {
let capitalWeekday = weekdayDue.charAt(0).toUpperCase() +
weekdayDue.slice(1);
if (toDoList[capitalWeekday] === undefined) {
let subArr = [];
toDoList[capitalWeekday] = subArr.concat(task);
} else {
toDoList[capitalWeekday].push(task);
}
}
and here is the code as I have it now. Clearly it is not producing the correct result:
function remove(task, weekdayDue) {
let capitalWeekday = weekdayDue.charAt(0).toUpperCase() +
weekdayDue.slice(1);
delete toDoList.capitalWeekday[task]
//the below code is working; i want to send this to another
array
if (archivedList[capitalWeekday] === undefined) {
let subArr = [];
archivedList[capitalWeekday] = subArr.concat(task);
} else {
archivedList[capitalWeekday].push(task);
}
};
add('laundry', 'monday');
add('wash car', 'monday');
add ('vacuum', 'tuesday');
add('run errands', 'wednesday');
add('grocery shopping', 'wednesday');
// the output is: { Monday: [ 'laundry', 'wash car' ],
Tuesday: [ 'vacuum' ],
Wednesday: [ 'run errands', 'grocery shopping' ] }
Then let's say I want to remove 'wash car' from Monday I was trying:
remove('wash car', 'monday');
console.log(toDoList)
// The output is an empty object {}
I personally would refactor a bit your code, but I've worked a bit around it to fix some issues.
First of all, you shouldn't use delete for your scenario, because it will reset the item at the nth position of the array with the default value, which is undefined.
Usually, for that kind of operations, since you deal with strings, you rather take a look at the first occurrence of your item in the array, take its index, and use splice (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) to actually remove the item from the array.
In this way, you end up with a clean array without invalid items in it.
Below is the working code (with the mentioned fixes) that does what you asked. As a side note, I would suggest you to avoid working with strings for such purposes, but I would rather tackle objects with unique ids, so that it's significantly easier to keep track of them between arrays and objects.
Additionally, there are some cases that you didn't think about, for instance I can think about calling remove by giving an invalid task, so you may work a bit around the code below to handle the case where taskIndex is -1 (meaning that no item was found with that index).
var toDoList = {}, archivedList = {};
function add(task, weekdayDue) {
let capitalWeekday = weekdayDue.charAt(0).toUpperCase() + weekdayDue.slice(1);
if (toDoList[capitalWeekday] === undefined) {
let subArr = [];
toDoList[capitalWeekday] = subArr.concat(task);
} else {
toDoList[capitalWeekday].push(task);
}
}
function remove(task, weekdayDue) {
let capitalWeekday = weekdayDue.charAt(0).toUpperCase() + weekdayDue.slice(1);
let taskIndex = toDoList[capitalWeekday].indexOf(task);
toDoList[capitalWeekday].splice(taskIndex, 1);
//delete toDoList[capitalWeekday][taskIndex];
if (archivedList[capitalWeekday] === undefined) {
let subArr = [];
archivedList[capitalWeekday] = subArr.concat(task);
} else {
archivedList[capitalWeekday].push(task);
}
};
add('test', 'monday');
add('wash car', 'monday');
remove('wash car', 'monday');
console.log(toDoList);
console.log(archivedList);
You are on the right path. Maybe the trouble you had with filter is because filter will return a new Array and not modify the current one. You could update your remove function and replace the line:
delete toDoList.capitalWeekday[task]
with
toDoList.capitalWeekday = toDoList.capitalWeekday.filter((item) => {return item !== task});
function remove(task, weekdayDue) {
let capitalWeekday = weekdayDue.charAt(0).toUpperCase() +
weekdayDue.slice(1);
// Assign new array with all elements but task
toDoList[capitalWeekday] = toDoList[capitalWeekday].filter(i => i !== task)
};
add('foo'...
add('bar'...
"{
"Baz": [
"Foo",
"Bar"
]
}"
remove('foo'...
"{
"Baz": [
"Bar"
]
}"

Categories