Sequelize.js get orders divided by the status - javascript

I have a Node.JS project and am using sequelize as the ORM.
I would like to run a query where I get all of my orders grouped by the status. So I would get for example an object with 5 keys (given that I have 5 different statuses). And in each key there would be an array with all orders that have that status.
Example of object:
{
"Done": [{id:1, item: "bag"}, {id:2, item: "purse"}],
"Processing": [{id:3, item: "bag"}, {id:4, item: "purse"}],
"Pending": [{id:5, item: "bag"}, {id:6, item: "purse"}]
}
Is this possible in any way or I need to get all possible statuses and just run the same number of queries each time changing the where clause?
Thanks

.findAll() gives you back a result set consisting of an array of model instances. I guess in your case it will be an array of Orders. It's flattened, not hierarchical.
That will look something like this.
[
{status: "Done", id:1, item: "bag"},
{status: "Done", id:2, item: "purse"},
{status: "Processing", id:3, item: "bag"},
{status: "Processing", id:4, item: "purse"},
{status: "Pending", id:5, item: "bag"},
{status: "Pending", id:6, item: "purse"}
]
You can then turn that flattened result set into the hierarchical one you want. Something like this, not debugged, should do the job.
const byStatus = {}
for (const row of resultSet) {
/* first time we've seen this status value? if so create an array for it. */
if (!byStatus[row.status]) byStatus[row.status] = []
/* put the present row into the appropriate array */
byStatus[row.status].push( {id: row.id, item: row.item })
}
That way you can run just one .findAll() query. That's a good idea because it's more efficient than running multiple ones.

You need to use a "native" query with a GROUP BY clause or you fetch the data normally and do the gruoping in JS/TS using lodash's groupBy.

Related

Mongodb sort Aggregation in same order ids was passed on filter

I would like to know if its possible to keep the current order of the result the same as it is passed in on the filtering.
So lets say we have an array of IDS:
var arrayValues = [1,3,2]
I would like to aggregate the values but keep the result same order as im passing in the above array.
var result = Item.aggregate([{ $match: { _id: { $in: arrayValues } }}])
I would want the result in same order as the array values passed in as _id value.
Example Result :
result = [{ _id: 1 },{ _id: 3 },{ _id: 2 }]
You can use indexOfArray for this:
db.collection.aggregate([
{$match: {_id: {$in: arrayValues}}},
{$set: {index: {$indexOfArray: [arrayValues, "$_id"]}}},
{$sort: {index: 1}},
{$unset: "index"}
])
See how it works on the playground example

How to create "products filter" efficiently in Node.js and Angular?

I'm creating an angular application (computer online store) with a node/express backened. I have a products page to display all the products in my DB. A product has this model (typescript):
interface Product {
name: string
properties: {name: string, value: string | number}[]
}
I have a section within the page where you can filter products by properties. for instance a user can filter all the CPUs that have 4 cores or 8 cores. right now this is implemented like this:
In the angular application i query ALL THE PRODUCTS of the requested category,
loop through all of them, collect their properties and all the possible values and filter like this...
const products = [
{
name: 'intel cpu 1',
properties: [
{name: 'cores', value: 8},
{name: 'clock speed', value: 2.6}
]
},
{
name: 'intel cpu 2',
properties: [
{name: 'cores', value: 4},
{name: 'clock speed', value: 1.2}
]
}
]
collectPropertiesFromProducts(products)
// RESULT:
[
{property: 'cores', possibleValues: [4,8]},
{property: 'clock speed', possibleValues: [1.2,2.6]}
]
For now it works great, i can filter products easily by the result and it is all dynamic (i can just add a property to a product and thats it).
The problem is that it scales VERY BADLY, because:
I have to query all of the products to know their properties
The more products/properties = more CPU time = blocks main thread
My question is how can i do better? i have a node server so moving all the logic to there its pretty useless, i could also just move the "property collecting" function to a worker thread but again, ill have to query all the products...
Instead of dealing with this in the client or in the service itself, you can let mongodb do the calculations for you. E.g. you could write the following aggregation:
db.getCollection('products').aggregate([{
$unwind: "$properties"
},
{
$project: {
name: "$properties.name",
total: {
$add: ["$properties.value", ]
}
}
}, {
$group: {
_id: "$name",
possibleValues: {
$addToSet: "$total"
}
}
}
])
You could then expose this query through a custom endpoint (e.g. GET /product-properties) on your node-server and consume the response on the client.
You should consider doing multiple requests to the backend:
First:
getQueryParams, a new endpoint which returns your RESULT
Second:
A none filtered request to receive the initial set of products
Third:
When select a filter (based on first request) you do a new request with the selected filter

Using Knex, how can the relevant rows of a joined table be given as a nested object?

Using knex, how can I get a user's relevant row from the users table along with an Array of all the groups for a user with the id=1?
This is my users table:
This is my groups table:
And this is my users_groups association table:
…I am running this query but it's returning 3 separate rows for the same user:
db("users").join("users_groups", "users.id", "=", "users_groups.user_id").join("groups", "groups.id", "=", "users_groups.group_id").where("users.id", "=", 1)
which I believe translates to:
select * from users inner join users_groups on users.id = users_groups.user_id inner join groups on groups.id = users_groups.group_id where users.id=1
The SQL returns:
It's currently returning:
Array(3) [Object, Object, Object]
length:3
__proto__:Array(0) [, …]
0:Object {email:"raj#raj.raj" group_id:1, id:1, name:"step 1", name:"r", role:"superadmin", user_id:1, username:"raj"}
1:Object {email:"raj#raj.raj" group_id:2, id:1, name:"step 2", name:"r", role:"superadmin", user_id:1, username:"raj"}
2:Object {email:"raj#raj.raj" group_id:3, id:1, name:"step 3", name:"r", role:"superadmin", user_id:1, username:"raj"}
Stringified, it looks like this
"[{"id":1,"name":"step 1","email":"raj#raj.raj","username":"raj","password":"$2b$10$GbbLTP2sEPS7OKmR4l8RSeX/PUmoIFyNBJb1RIIIrbZa1NNwolHFK","role":"superadmin","created_at":"2020-04-14T12:45:38.138Z","user_id":1,"group_id":1},{"id":2,"name":"step 2","email":"raj#raj.raj","username":"raj","password":"$2b$10$GbbLTP2sEPS7OKmR4l8RSeX/PUmoIFyNBJb1RIIIrbZa1NNwolHFK","role":"superadmin","created_at":"2020-04-14T12:45:38.138Z","user_id":1,"group_id":2},{"id":3,"name":"step 3","email":"raj#raj.raj","username":"raj","password":"$2b$10$GbbLTP2sEPS7OKmR4l8RSeX/PUmoIFyNBJb1RIIIrbZa1NNwolHFK","role":"superadmin","created_at":"2020-04-14T12:45:38.138Z","user_id":1,"group_id":3}]"
I'd rather have it return an object representing the single user row, with a nested object for the 3 relevant rows from the groups table. For example:
{id:1, name:"raj", groups:[{id:1, name:"step 1"}, {id:2,name:"step 2"}, {id:3,name:"step 3"}]}
Is this possible? Or would multiple queries be required and how wasteful is that?
Knex is not able to aggregate flat data as you needed. You should do it yourself.
(await db('users')
.join('users_groups', 'users.id', '=', 'users_groups.user_id')
.join('groups', 'groups.id', '=', 'users_groups.group_id')
.where('users.id', '=', 1)
)
.reduce((result, row) => {
result[row.id] = result[row.id] || {
id: row.id,
username: row.username,
email: row.email,
groups: [],
};
result[row.id].groups.push({ id: row.group_id, name: row.name });
return result;
}, {});

Modify array so it will contain data under unique username

I have array that contains plenty of data. Format is always like that:
1:
UserName: "John Smith"
Priority: "2"
Time Occured: "02/09/2019 11:20:23"
Time Ended: "02/09/2019 11:20:23"
2:
UserName: "Tom Bill"
Priority: "4"
Time Occured: "01/08/2019 13:20:23"
Time Ended: "04/08/2019 15:20:23"
3:
UserName: "John Smith"
Priority: "2"
Time Occured: "06/08/2019 13:20:23"
Time Ended: "09/09/2019 15:20:23"
...
Of course there is more stuff, but just to give you idea of structure.
Array contains entries that might be under the same user name. As user can have multiple entries
What I want to do, is sort and modify it to the way I can use it on data table. I am not sure what approach might be the best or what is possible.
I was thinking that I need to modify array do some math in meantime. So in Data table I can present that John Smith, got 8 entries, two of them are sev 4 etc etc. Tom Bill got 4 entries etc. Basically I won't use original data as I need to modify some parts of it, for Example I am not interested in date itself, but if it was in the past or in the future, already got scripts for that, yet I need to do it for every single user.
A structure something like this seems to be sufficient for your requirement:
data = {
'John Smith' : [{ Priority : 1, .... }, { ...2nd instance }],
'John Doe' : [{...1st instance of John Doe}],
}
Basically an object that has the names for keys, and each key has an array of entries of data.
Whenever you wish to add more entries to John Smith, you get access to the array directly by using data['John Smith']
EDIT
To convert the data to this format.
data = [
{
'UserName': "John Smith",
'Priority': "2",
'Time Occured': "02/09/2019 11:20:23",
'Time Ended': "02/09/2019 11:20:23",
},
{
'UserName': "Tom Bill",
'Priority': "4",
'Time Occured': "01/08/2019 13:20:23",
'Time Ended': "04/08/2019 15:20:23",
},
{
'UserName': "John Smith",
'Priority': "2",
'Time Occured': "06/08/2019 13:20:23",
'Time Ended': "09/09/2019 15:20:23",
}
]
convertData = (data) =>{
let newData = {}
for(let i = 0; i<data.length; i++){
// console.log(data[i])
let name = data[i]['UserName']
tempData = {
'Priority' : data[i]['Priority'],
'Time Occured' : data[i]['Time Occured'],
//Add more properties here
}
if (newData[name]==null){
newData[name] = []
}
newData[name] = [...newData[name], tempData]
}
console.log(newData)
}
convertData(data)
Look at this codepen.
https://codepen.io/nabeelmehmood/pen/jONGQmX

Combine 2 different javascript json objects into one with a loop and joining on the questionid ,

So I am trying to combine 2 different javascript object than I can end up using in an angularjs ng-repeat . since there is a 1 to many relationship from the database, I was pulling queries separately.
What I have is this:
Main list of data , 3 object sample
0: Object
$$hashKey: "object:4"
Active:true
QuestionId:2
SalesChannel:"DTD"
1: Object
$$hashKey: "object:5"
Active:true
QuestionId:3
SalesChannel:"DTD"
2: Object
$$hashKey: "object:6"
Active:true
QuestionId:5
SalesChannel:"DTD"
Then another query returned data into what I want to relate as JSON into the other object
Object { Id: 3, Name: "Text box" QuestionId: 3}
{ Id: 4, Name: "Text box" QuestionId: 3}
{ Id: 9, Name: "Text box" QuestionId: 5}
So since I have both of these objects , I am wanting to combine.
Naturally I would think that I should return from the database, but then I also think about looping over and appending
for loop on main
{
.... find where main.QuestionId = sub.QuestionId and it to be added in as a nested object of json type...
Thus the end result SHOULD look like
[{
Active:true,
QuestionId: 3
SubData: [ {
Id: 3,
Name: "TextBox
QuestionId:3
},
{
Id: 4,
Name: "TextBox
QuestionId:3
}],
SalesChannel: "DTD"
}]
// and so on
How can i achieve this?
You want to go through all of the main objects, and assign to them only those results from second query. Use Array.prototype.forEach to go through them all, and Array.prototype.filter to select only appropriate results from secondary query.
firstQueryResult.forEach((firstObject)=>
firstObject.subdata = secondQueryResult.filter((secondObject)=>
secondObject.QuestionId === firstObject.QuestionId))
BTW, this has nothing to do with angularjs
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

Categories

Resources