SQL-joining of two or more arrays in JavaScript - javascript

I have one-page web app with few arrays, that are logically linked: records from "users" refers to records in "user_types", "charges" refers to "users", etc:
var users = [
{ id: "u0001", name: "John", user_type_id: "1" },
{ id: "u0002", name: "Bob", user_type_id: "1" },
{ id: "u0003", name: "Alice", user_type_id: "5" },
{ id: "u0004", name: "Jennifer", user_type_id: "5" },
// ... more
];
var user_types = [
{ id: "1", name: "Regular Clients"},
{ id: "5", name: "VIP Clients"},
// ... more
];
var charges = [
{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
{ id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
{ id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
{ id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
{ id: "7469", user_id: null , date: "2016-01-01", amount: "3.99", },
// ... more
];
I need to display them in linked manner, similar to the product of following SQL:
SELECT
charges.date,
charges.amount,
users.name,
user_types.name
FROM
charges
LEFT OUTER JOIN users ON users.id = charges.user_id
LEFT OUTER JOIN user_types ON user_types.id = users.user_type_id
I know I can create API call with this SQL query on server, but I would like to avoid that because tables are already loaded in the web app.
What is the simplest way to join them in memory?

If small library is OK, this can be done with StrelkiJS:
var users = new StrelkiJS.IndexedArray();
users.loadArray([
{ id: "u0001", name: "John", user_type_id: "1" },
{ id: "u0002", name: "Bob", user_type_id: "1" },
{ id: "u0003", name: "Alice", user_type_id: "5" },
{ id: "u0004", name: "Jennifer", user_type_id: "5" },
// ... more
]);
var user_types = new StrelkiJS.IndexedArray();
user_types.loadArray([
{ id: "1", name: "Regular Clients"},
{ id: "5", name: "VIP Clients"},
// ... more
]);
var charges = new StrelkiJS.IndexedArray();
charges.loadArray([
{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
{ id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
{ id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
{ id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
{ id: "7469", user_id: null , date: "2016-01-01", amount: "3.99", },
// ... more
]);
var result = charges.query([{
from_col: "user_id",
to_table: users,
to_col: "id",
type: "outer",
join: [{
from_col: "user_type_id",
to_table: user_types,
to_col: "id",
type: "outer",
}]
}])
Result will be joined array of following structure:
[
[
{"id":"7443","user_id":"u0001","date":"2016-01-01","amount":"3.99"},
{"id":"u0001","name":"John","user_type_id":"1"},
{"id":"1","name":"Regular Clients"}
],
[
{"id":"7445","user_id":"u0001","date":"2016-01-01","amount":"4.02"},
{"id":"u0001","name":"John","user_type_id":"1"},
{"id":"1","name":"Regular Clients"}
],
[
{"id":"7448","user_id":"u0001","date":"2016-01-01","amount":"6.99"},
{"id":"u0001","name":"John","user_type_id":"1"},
{"id":"1","name":"Regular Clients"}
],
[
{"id":"7453","user_id":"u0003","date":"2016-01-01","amount":"3.00"},
{"id":"u0003","name":"Alice","user_type_id":"5"},
{"id":"5","name":"VIP Clients"}
],
[
{"id":"7469","user_id":null,"date":"2016-01-01","amount":"3.99"},
null,
null
]
]

If you can modify the way users and user_types are being populated then you can do this pretty quickly.
You would need to change users and user_types to objects so you have something like this:
// make users an object with the id as the key
var users = {
"u0001" : { name: "John", user_type_id: "1" },
"u0002" : { name: "Bob", user_type_id: "1" },
"u0003" : { name: "Alice", user_type_id: "5" },
"u0004" : { name: "Jennifer", user_type_id: "5" }
};
// same for user_types
var user_types = {
"1" : { name: "Regular Clients" },
"5" : { name: "VIP Clients" }
};
var charges = [
{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
{ id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
{ id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
{ id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
{ id: "7469", user_id: null , date: "2016-01-01", amount: "3.99", }
];
// now you can just loop through and use object key lookups:
var out = [];
for(var i = 0, numCharges = charges.length; i < numCharges; ++i)
{
var currentCharge = charges[i];
if(currentCharge.user_id === null) continue;
out.push([
currentCharge.date,
currentCharge.amount,
// get the current charges user_id and look up the name from users
users[currentCharge.user_id].name,
// same as above but use the user_type_id to get the user_type name
user_types[users[currentCharge.user_id].user_type_id].name
]);
}
console.log(out);

This proposal features IMTheNachoMan solution, with the extension of generation necessary objects from the given data.
It includes all rows of charges, because with SQL, the rows are returned too.
The problem with null values are here tested and null is then returned.
var users = [{ id: "u0001", name: "John", user_type_id: "1" }, { id: "u0002", name: "Bob", user_type_id: "1" }, { id: "u0003", name: "Alice", user_type_id: "5" }, { id: "u0004", name: "Jennifer", user_type_id: "5" }],
user_types = [{ id: "1", name: "Regular Clients" }, { id: "5", name: "VIP Clients" }],
charges = [{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", }, { id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", }, { id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", }, { id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", }, { id: "7469", user_id: null, date: "2016-01-01", amount: "3.99", }],
user = Object.create(null),
type = Object.create(null),
result;
users.forEach(function (u) {
user[u.id] = u;
});
user_types.forEach(function (t) {
type[t.id] = t;
});
result = charges.map(function (charge) {
return {
'charges.date': charge.date,
'charges.amount': charge.amount,
'users.name': charge.user_id === null ? null : user[charge.user_id].name,
'user_types': charge.user_id === null ? null : type[user[charge.user_id].user_type_id].name,
};
});
console.log(result);

Make users a map, so you can use users['u0001']. Then loop through charges and do users[current_charge.user_id].charges.push(current_charge). Each user in users should have a charges property initialized as an empty array. You can do that when you turn the users array into a id => user map.
You don't need anything special here, just two loops through users and charges:
var users_map = {};
var i;
for(i = 0; i < users.length; i++) {
users_map[users[i].id] = users[i];
users_map[users[i].id].charges = [];
}
for(i = 0; i < charges.length; i++) {
users_map[charge[i].user_id].charges.push(charge[i]);
}
If you really need the final "result" to be an array, not a map, you can loop through users_map again and turn it into an array.
A really simple solution leveraging modern JS stuff would be this:
var joined_data = Object.keys(users_map).map(function (key) {
return users_map[key];
});
You can make the above code a lot prettier with lodash or another similar library.

The only way to do this without restructuring the objects is to loop and filter.
You can optimise it slightly by processing the users and their types first, but that's about it...
var users = [
{ id: "u0001", name: "John", user_type_id: "1" },
{ id: "u0002", name: "Bob", user_type_id: "1" },
{ id: "u0003", name: "Alice", user_type_id: "5" },
{ id: "u0004", name: "Jennifer", user_type_id: "5" },
// ... more
];
var user_types = [
{ id: "1", name: "Regular Clients"},
{ id: "5", name: "VIP Clients"},
// ... more
];
var charges = [
{ id: "7443", user_id: "u0001", date: "2016-01-01", amount: "3.99", },
{ id: "7445", user_id: "u0001", date: "2016-01-01", amount: "4.02", },
{ id: "7448", user_id: "u0001", date: "2016-01-01", amount: "6.99", },
{ id: "7453", user_id: "u0003", date: "2016-01-01", amount: "3.00", },
{ id: "7469", user_id: null , date: "2016-01-01", amount: "3.99", },
// ... more
];
// pre-process users
var usersPlusTypes = users.map(function(u) {
var foundUserTypes = user_types.filter(function(ut) {
return ut.id == u.user_type_id;
});
return {
id: u.id,
user: u,
userType: foundUserTypes.length ? foundUserTypes[0] : null
}
})
// now link charges to users
var results = charges.map(function(c) {
var user = usersPlusTypes.filter(function(upt) {
return upt.id == c.user_id;
});
return {
date: c.date,
amount: c.amount,
userName: user.length ? user[0].user.name : null,
userTypeName: user.length && user[0].userType ? user[0].userType.name : null,
};
});
console.log(results);

Related

how filter array of objects with same name and status in JS

Hi all I have following code
[
{service: { name: "Home" },status: "Generated", feeCharged:{id:1,fee:2},
{service: { name: " Photography" },status: "requested",feeCharged:{id:2,fee:24}},
{service: { name: "Electrical" },status: "requested",feeCharged:{id:6,fee:42}},
{service: { name: "Electrical" },status: "Completed",feeCharged:{id:66,fee:23} },
{service: { name: " Photography" },status: "Completed",feeCharged:{id:78,fee:11}},
{service: { name: "Home" },status: "Generated",feeCharged:{id:45,fee:234}},
{service: { name: "Electrical" }, status: "requested",feeCharged:{id:77,fee:3} },
{service: { name: "Electrical" }, status: "requested",feeCharged:{id:4,fee:33} }
]
Now I am trying to filter them in new array by service.name and by status and add count.
The final result should be:
[
{ name: "Home", status: "Generated", count: 2 },
{ name: "Photography", status: "requested", count: 1 },
{ name: "Photography", status: "Completed", count: 1 },
{ name: "Electrical", status: "requested", count: 3 },
{ name: "Electrical", status: "Completed", count: 1 }
]
So as you see in my final result if there are same service.name and status I am merging them into one object and setting count.
For filtering I try this, but it not working as I expected:
let answer = [];
data.forEach((x) => {
if (!answer.some((y) => y.name === x.service.name)) {
let newAnswer = {};
newAnswer.name = x.service.name;
newAnswer.value = 1;
answer.push(newAnswer);
} else {
let existAnswer = answer.find((y) => y.name === x.service.name);
existAnswer.value++;
}
});
Please help me to achieve that result, thanks.
Maybe this will be helpful for you?
const data = [{ service: { name: "Home" }, status: "Generated", feeCharged: { id: 1, fee: 2 }},{ service: { name: " Photography" }, status: "requested", feeCharged: { id: 2, fee: 24 } }, { service: { name: "Electrical" }, status: "requested", feeCharged: { id: 6, fee: 42 } }, { service: { name: "Electrical" }, status: "Completed", feeCharged: { id: 66, fee: 23 } }, { service: { name: " Photography" }, status: "Completed", feeCharged: { id: 78, fee: 11 } }, { service: { name: "Home" }, status: "Generated", feeCharged: { id: 45, fee: 234 } }, { service: { name: "Electrical" }, status: "requested", feeCharged: { id: 77, fee: 3 } }, { service: { name: "Electrical" }, status: "requested", feeCharged: { id: 4, fee: 33 } }];
const res = Object.entries(data.reduce((a, e, nam) => { // get counts of name/status combinations
nam = e.service.name + "|" + e.status;
a[nam] = (a[nam] ?? 0) + 1;
return a;
}, {})).map(([k, n], t) =>{ // separate name/status key values again ...
t = k.split("|");
return {name: t[0],status: t[1],count: n};
})
console.log(res)
(The current implementation uses | as a delimiter between the name and status value. Therefore it will fail if a name or status value contains this character.)

Select the latest unique object from array of objects : Javascript

I am having array of objects with the following structure
const arr = [
{ id: 0, name: "abc", userid: "0", lastseen: 1645079273000 },
{ id: 3, name: "pqr", userid: "456", lastseen: 1645079273008 },
{ id: 1, name: "lmn", userid: "123", lastseen: 1645079273001 },
{ id: 3, name: "pqr", userid: "456", lastseen: 1645079273002 },
{ id: 4, name: "xyz", userid: "123", lastseen: 1645079273003 },
];
I want to return the objects where userid that is unique with latest entry should be returned. Ideally I might get userId as string 0. so to remove that added a filter clause
My approach:
const result = [...new Map(arr.filter(node=>node.userid!=="0").map(node=>[node.userid, node])).values()];
Output expected
[
{ id: 4, name: "xyz", userid: "123", lastseen: 1645079273003 },
{ id: 3, name: "pqr", userid: "456", lastseen: 1645079273008 },
]
Array.reduce implementation.
Logic
Run a loop on tha array using Array.reduce.
Create an object and update the value against key userId.
Produce the Array.values of this generated object. This will give you the unique list of values.
const arr = [
{ id: 0, name: "abc", userid: "0", lastseen: 1645079273000 },
{ id: 3, name: "pqr", userid: "456", lastseen: 1645079273008 },
{ id: 1, name: "lmn", userid: "123", lastseen: 1645079273001 },
{ id: 3, name: "pqr", userid: "456", lastseen: 1645079273002 },
{ id: 4, name: "xyz", userid: "123", lastseen: 1645079273003 },
];
const result = Object.values(arr.reduce((acc, curr) => {
if (curr.userid !== "0") {
acc[curr.userid] = acc[curr.userid] && acc[curr.userid].lastseen ?
acc[curr.userid].lastseen < curr.lastseen ? curr : acc[curr.userid] : curr;
}
return acc;
}, {}));
console.log(result)

How to check if array of objects that contains another array of object has property

Hi I have an array of objects which contains another array of objects.
I need to find an object in array which contains another object in it's array with certain propery
ID.
Let's say i need to find an object in casses array which contains a user with certain ID.
ID for user is unique.
casses = [
{
caseName: 'case 1',
date: '2021-05-4',
id: '123',
user: [{name: 'Vlad', id: '1'}, {name: 'Misha', id: '2'}]
},
{
caseName: 'case 2',
date: '2021-05-4',
id: '123',
user: [{name: 'Alina', id: '3'}, {name: 'Alex', id: '4'}]
},
{
caseName: 'case 3',
date: '2021-05-4',
id: '123',
user: []
},
]
I could use a nested loops and so on. But i wondering is it possible to do with one line ?
Something like this but one level deeper:
let val = casses(item => item.id === element.id); ​
Assume your case with ID set to "3"
Try below
const ID = "3";
const casses = [
{
caseName: "case 1",
date: "2021-05-4",
id: "123",
user: [
{ name: "Vlad", id: "1" },
{ name: "Misha", id: "2" }
]
},
{
caseName: "case 2",
date: "2021-05-4",
id: "123",
user: [
{ name: "Alina", id: "3" },
{ name: "Alex", id: "4" }
]
},
{
caseName: "case 3",
date: "2021-05-4",
id: "123",
user: []
}
];
casses.find(item => item.user.some(subItem => subItem.id === ID));

Please help to Convert Array to Object

I need to convert an array with only ids and an object with Id & Name need to find object array element from the object and create new Object
App.js:
["111","114","117']
Object:
[
{ id: "111", Name: "Jerry" },
{ id: "112", Name: "Tom" },
{ id: "113", Name: "Mouse" },
{ id: "114", Name: "Minny" },
{ id: "115", Name: "Mayavi" },
{ id: "116", Name: "Kuttoosan" },
{ id: "117", Name: "Raju" }
];
Result Need:
[
{ id: "111", Name: "Jerry" },
{ id: "114", Name: "Minny" },
{ id: "117", Name: "Raju" }
];
const array = ["111", "114", "117"];
const object = [
{ id: "111", Name: "Jerry" },
{ id: "112", Name: "Tom" },
{ id: "113", Name: "Mouse" },
{ id: "114", Name: "Minny" },
{ id: "115", Name: "Mayavi" },
{ id: "116", Name: "Kuttoosan" },
{ id: "117", Name: "Raju" }
];
const result = object.filter(o => array.includes(o.id));
This should give you the result you want, pay attention that what you called object actually is an array of objects, as far as i understood you want keep only the object with an id contained in the first array, so as i shown just filter them
I think you can just use .filter() to achieve the same result.
const targetIds = ["111","114","117"];
const nameObjects = [{id:"111", Name:"Jerry"}, {id:"112", Name:"Tom"}, {id:"113", Name:"Mouse"}, {id:"114", Name:"Minny"}, {id:"115", Name:"Mayavi"}, {id:"116", Name:"Kuttoosan"}, {id:"117", Name:"Raju"}];
const filtered = nameObjects.filter((obj) => targetIds.indexOf(obj.id) !== -1);
// Which should give the result you need
// [{id:"111", Name:"Jerry"}, {id:"114", Name:"Minny"},{id:"117", Name:"Raju"}]
Use the .filter() to get the result
const ids = ["111", "114", "117"];
const nameids = [
{ id: "111", Name: "Jerry" },
{ id: "112", Name: "Tom" },
{ id: "113", Name: "Mouse" },
{ id: "114", Name: "Minny" },
{ id: "115", Name: "Mayavi" },
{ id: "116", Name: "Kuttoosan" },
{ id: "117", Name: "Raju" }
];
const result = nameids.filter(res => ids.includes(res.id));
console.log(result);

How to create a nested array of object from an array of objects

How Can I loop through this array of objects and change it so that the individual menu items are nested in the object menu_name?
const menus = [
{ menu_name: 'Entre', id:0 },
{
name: 'Soup',
price: 14.99,
id:1
},
{
name: 'Chips & Salsa',
price: 7.99,
id:2
},
{
name: 'Chicken Nuggets',
price: 12.99,
id:3
},
{ menu_name: 'Sides', id:4 },
{
name: 'Fries',
price: 4.99,
id:5
},
{
name: 'Drinks',
price: 2.99,
id:6
},
{
name: 'Onion Rings',
price: 5.99,
id:7
},
];
the end result should look like this for each menu_name object, where an array of menus is nested in the menu_name object
{
menu_name: 'Sides',
menu: [
{
name: 'Fries',
price: 4.99,
},
{
name: 'Drinks',
price: 2.99,
},
{
name: 'Onion Rings',
price: 5.99,
},
],
},
You can easily achieve this using reduce and object destructuring
const menus = [
{ menu_name: "Entre", id: 0 },
{
name: "Soup",
price: 14.99,
id: 1,
},
{
name: "Chips & Salsa",
price: 7.99,
id: 2,
},
{
name: "Chicken Nuggets",
price: 12.99,
id: 3,
},
{ menu_name: "Sides", id: 4 },
{
name: "Fries",
price: 4.99,
id: 5,
},
{
name: "Drinks",
price: 2.99,
id: 6,
},
{
name: "Onion Rings",
price: 5.99,
id: 7,
},
];
const result = menus.reduce((acc, curr) => {
const { menu_name } = curr;
if (menu_name) {
acc.push({ menu_name, menu: [] });
} else {
const { name, price } = curr;
acc[acc.length - 1].menu.push({ name, price });
}
return acc;
}, []);
console.log(result);
var newMenu = [];
menus.forEach(menu=>{
if(menu.menu_name){
newMenu.push({...menu, menu: []})
}else{
newMenu[newMenu.length-1].menu.push(menu)
}
});

Categories