Join two objects just like SQL inner join - javascript

I have two objects like:
countries = [
{ id: 1, name: 'India', image: 'thumb15.jpg' },
{ id: 2, name: 'Africa', image: 'thumb11.jpg' },
{ id: 3, name: 'Kenya', image: 'thumb10.jpg' }
];
cities = [
{ id: 1, name: 'Ahmedabad', country_id: 1 },
{ id: 2, name: 'Vadodara', country_id: 1 },
{ id: 3, name: 'Cairo', country_id: 2 },
{ id: 4, name: 'Kinshasa', country_id: 2 },
{ id: 5, name: 'Luanda', country_id: 2 },
{ id: 6, name: 'Nairobi', country_id: 3 },
{ id: 7, name: 'Nakuru', country_id: 3 },
{ id: 8, name: 'Mombasa', country_id: 3 },
];
I want to combine these two Objects, just like SQL have INNER JOIN
for example, I want to perform below operation (query) on the above two objects,
SELECT * from countries INNER JOIN cities ON cities.country_id = countries.id
and my expected output will look like:
expected_result = [
{ id: 1, name: "Ahmedabad", country_id: 1, country_name: "India", country_image: "thumb15.jpg" },
{ id: 2, name: "Vadodara", country_id: 1, country_name: "India", country_image: "thumb15.jpg" },
{ id: 3, name: "Cairo", country_id: 2, country_name: "Africa", country_image: "thumb11.jpg" },
{ id: 4, name: "Kinshasa", country_id: 2, country_name: "Africa", country_image: "thumb11.jpg" },
{ id: 5, name: "Luanda", country_id: 2, country_name: "Africa", country_image: "thumb11.jpg" },
{ id: 6, name: "Nairobi", country_id: 3, country_name: "Kenya", country_image: "thumb10.jpg" },
{ id: 7, name: "Nakuru", country_id: 3, country_name: "Kenya", country_image: "thumb10.jpg" },
{ id: 8, name: "Mombasa", country_id: 3, country_name: "Kenya", country_image: "thumb10.jpg" }
];
Thanks in advance.

It is possible to use map function and Map collection to get desired country:
const uniqueCountries = new Map(countries.map(s => [s.id, s]));
const result = cities.map(s => ({ ...s,
country_name: uniqueCountries.get(s.country_id).name }));
An example:
let countries = [
{ id: 1, name: 'India', image: 'thumb15.jpg' },
{ id: 2, name: 'Africa', image: 'thumb11.jpg' },
{ id: 3, name: 'Kenya', image: 'thumb10.jpg' }
];
let cities = [
{ id: 1, name: 'Ahmedabad', country_id: 1 },
{ id: 2, name: 'Vadodara', country_id: 1 },
{ id: 3, name: 'Cairo', country_id: 2 },
{ id: 4, name: 'Kinshasa', country_id: 2 },
{ id: 5, name: 'Luanda', country_id: 2 },
{ id: 6, name: 'Nairobi', country_id: 3 },
{ id: 7, name: 'Nakuru', country_id: 3 },
{ id: 8, name: 'Mombasa', country_id: 3 },
];
const uniqueCountries = new Map(countries.map(s => [s.id, s]));
const result = cities.map(s => ({ ...s,
country_name: uniqueCountries.get(s.country_id).name }));
console.log(result);
UPDATE:
map method creates new array from the calling array. In addition, you can add new properties to your object you want:
let countries = [
{ id: 1, name: 'India', image: 'thumb15.jpg' },
{ id: 2, name: 'Africa', image: 'thumb11.jpg' },
{ id: 3, name: 'Kenya', image: 'thumb10.jpg' }
];
const countriesWithShortCountryNames = countries.map(s=> ({...s,
shortName: s.name.substring(0, 3)}))
console.log(countriesWithShortCountryNames)
Map collection:
The Map object holds key-value pairs and remembers the original
insertion order of the keys.

You could take a hash table for all items of countries, where id is the key and the value is a new object in the wanted format.
{
1: {
country_name: "India",
image: "thumb15.jpg"
},
2: {
country_name: "Africa",
image: "thumb11.jpg"
},
3: {
country_name: "Kenya",
image: "thumb10.jpg"
}
}
Then map a new objects with the original key/value and new properties from the hash table.
Methods used, in order of appearance:
Array#reduce
destructuring assignment with assigning to new variable name
Array#map
var countries = [{ id: 1, name: 'India', image: 'thumb15.jpg' }, { id: 2, name: 'Africa', image: 'thumb11.jpg' }, { id: 3, name: 'Kenya', image: 'thumb10.jpg' }],
cities = [{ id: 1, name: 'Ahmedabad', country_id: 1 }, { id: 2, name: 'Vadodara', country_id: 1 }, { id: 3, name: 'Cairo', country_id: 2 }, { id: 4, name: 'Kinshasa', country_id: 2 }, { id: 5, name: 'Luanda', country_id: 2 }, { id: 6, name: 'Nairobi', country_id: 3 }, { id: 7, name: 'Nakuru', country_id: 3 }, { id: 8, name: 'Mombasa', country_id: 3 }],
countriesH = countries.reduce((r, { id, name: country_name, ...o }) =>
(r[id] = { country_name, ...o }, r), {}),
result = cities.map(o => ({ ...o, ...countriesH[o.country_id] }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

I wrote a library (which emulates dotnet's linq) which makes this a breeze:
import { blinq } from "blinq";
//...
const joinedData = blinq(countries)
.join(
cities,
co => co.id,
ci => ci.country_id,
(country, city) => ({ country, city })
)
.toArray();
const {
blinq
} = window.blinq;
const countries = [{
id: 1,
name: "India",
image: "thumb15.jpg"
},
{
id: 2,
name: "Africa",
image: "thumb11.jpg"
},
{
id: 3,
name: "Kenya",
image: "thumb10.jpg"
}
];
const cities = [{
id: 1,
name: "Ahmedabad",
country_id: 1
},
{
id: 2,
name: "Vadodara",
country_id: 1
},
{
id: 3,
name: "Cairo",
country_id: 2
},
{
id: 4,
name: "Kinshasa",
country_id: 2
},
{
id: 5,
name: "Luanda",
country_id: 2
},
{
id: 6,
name: "Nairobi",
country_id: 3
},
{
id: 7,
name: "Nakuru",
country_id: 3
},
{
id: 8,
name: "Mombasa",
country_id: 3
}
];
const joinedData = blinq(countries)
.join(
cities,
co => co.id,
ci => ci.country_id,
(country, city) => ({
country,
city
})
)
.toArray();
console.log(JSON.stringify(joinedData, null, 2))
<script src="https://cdn.jsdelivr.net/npm/blinq"></script>

Related

How to get values of child objects in an array of objects in javascript

states = [{
name: telangana,
cities: [{
id: 1,
name: foo
}, {
id: 2,
name: joo
}, {
id: 3,
name: goo
}]
},
{
name: punjab,
cities: [{
id: 4,
name: tyu
}, {
id: 5,
name: ery
}, {
id: 6,
name: doo
}]
},
{
name: mumbai,
cities: [{
id: 7,
name: eee
}, {
id: 8,
name: qqq
}, {
id: 9,
name: www
}]
},
]
I want response like [foo, joo, goo, tyu, ery,doo, eee,qqq,www]
Can someone help me ?
Just write one line:
Learn more about reduce() and map()
const states = [{ name: "telangana", cities: [{ id: 1, name: "foo" }, { id: 2, name: "joo" }, { id: 3, name: "goo" }] }, { name: "punjab", cities: [{ id: 4, name: "tyu" }, { id: 5, name: "ery" }, { id: 6, name: "doo" }] }, { name: "mumbai", cities: [{ id: 7, name: "eee" }, { id: 8, name: "qqq" }, { id: 9, name: "www" }] }, ];
const result = states.reduce((acc, { cities }) => [...acc, ...cities.map(({ name }) => name)], []);
console.log(result);
const getNames = (data) => {
const nameArr = [];
data.forEach((ele) => {
ele.cities.forEach((ele2) => {
nameArr.push(ele2.name);
})
})
return nameArr;
}
getNames(states);
Try this please!
states = [{
name: "telangana",
cities: [{
id: 1,
name: "foo"
}, {
id: 2,
name: "joo"
}, {
id: 3,
name: "goo"
}]
},
{
name: "punjab",
cities: [{
id: 4,
name: "tyu"
}, {
id: 5,
name: "ery"
}, {
id: 6,
name: "doo"
}]
},
{
name: "mumbai",
cities: [{
id: 7,
name: "eee"
}, {
id: 8,
name: "qqq"
}, {
id: 9,
name: "www"
}]
},
]
const wantedArray = []
for(i=0; i < states.length; i++){
for(j=0; j < states[i].cities.length; j++){
wantedArray.push(states[i].cities[j].name)
}
}
console.log(wantedArray)
Just give it an empty array, then you loop through the states indexes, each index in states will have a cities array, then you just need to loop it again in that array to get each name of the cities. From then, you are using the push method that Javascript provides to push it to the empty array.
Here's how I'm doing it in JSFiddle, there will have a better way to do this, too.

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)
}
});

Filter out data based off multiple user inputs

im working on filtering out data.
I'm having trouble extracting the text values in the tags property to compare it to the input array.
How would I build this in javascript?
let user_input =["Bananas", "Kiwi"]
const data= [
{
id: 18,
username: "james",
tags: [ { id: 1, text: "Bananas" }, { id: 2, text: "Mangos" }]
},
{
id: 17,
username: "anita",
tags: [ { id: 3, text: "Bananas" }, { id:4 , text: "Oranges" }, { id:5 , text: "Strawberries" } ]
},
{
id: 16,
username: "david",
tags: [ { id: 2, text: "Mangos" }]
},
{
id: 15,
username: "nicole",
tags: [ { id: 6, text: "Kiwi" }]
},
]
im expecting output to be [{id: 18 ...}, {id:17 ...}, {id:15 ...}]
You can use a filter() call, calling some() on the tags array of each iterated object to test if the user_input array includes() any of the text values of each iterated tags object.
const data = [{ id: 18, username: "james", tags: [{ id: 1, text: "Bananas" }, { id: 2, text: "Mangos" }] }, { id: 17, username: "anita", tags: [{ id: 3, text: "Bananas" }, { id: 4, text: "Oranges" }, { id: 5, text: "Strawberries" }] }, { id: 16, username: "david", tags: [{ id: 2, text: "Mangos" }] }, { id: 15, username: "nicole", tags: [{ id: 6, text: "Kiwi" }] },];
const user_input = ["Bananas", "Kiwi"];
const result = data.filter(({ tags }) =>
tags.some(({ text }) => user_input.includes(text)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If instead you wanted to only return objects that matched all the tags in the user_input array, you would instead call every() on user_input, map() the tags array of each iterated object to include only the text values, and then check that the returned array includes() each tag.
const data = [
{ id: 18, username: "james", tags: [{ id: 1, text: "Bananas" }, { id: 2, text: "Mangos" }] },
{ id: 17, username: "anita", tags: [{ id: 3, text: "Bananas" }, { id: 4, text: "Oranges" }, { id: 5, text: "Strawberries" }] },
{ id: 16, username: "david", tags: [{ id: 2, text: "Mangos" }] },
{
id: 15, username: "nicole",
tags: [
{ id: 6, text: "Kiwi" },
{ id: 6, text: "Bananas" }]
}
];
const user_input = ["Bananas", "Kiwi"];
const result = data.filter(({ tags }) =>
user_input.every(tag =>
tags
.map(({ text }) => text)
.includes(tag)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to first combine properties of an object then remove the duplicates in an array of objects using Javascript

I have an array of objects here:
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test2", quantity:1 },
{ id: 2, name: "test3", quantity:1 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:1 },
{ id: 5, name: "test7", quantity:1 },
{ id: 6, name: "test8", quantity:1 }
];
I want to add quantities of the duplicate objects together before removing them
So the result is:
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test3", quantity:2 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:2 },
{ id: 6, name: "test8", quantity:1 }
];
I have seen variations of it done removing duplicates using map or reduce but I haven't seen anything that can what I want to accomplish in an eloquent way without using too many loops.
I have been thinking about how to best accomplish this all day and haven't found anything, any help would be appreciated
You can use reduce with an object to store the element with each id.
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test2", quantity:1 },
{ id: 2, name: "test3", quantity:1 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:1 },
{ id: 5, name: "test7", quantity:1 },
{ id: 6, name: "test8", quantity:1 }
];
const res = Object.values(
arr.reduce((acc,curr)=>{
acc[curr.id] = acc[curr.id] || {...curr, quantity: 0};
acc[curr.id].quantity += curr.quantity;
return acc;
}, {})
);
console.log(res);
const arr = [
{ id: 1, name: "test1", quantity: 1 },
{ id: 2, name: "test2", quantity: 1 },
{ id: 2, name: "test3", quantity: 1 },
{ id: 3, name: "test4", quantity: 1 },
{ id: 4, name: "test5", quantity: 1 },
{ id: 5, name: "test6", quantity: 1 },
{ id: 5, name: "test7", quantity: 1 },
{ id: 6, name: "test8", quantity: 1 }
];
var result = arr.reduce(function (r, a) {
r[a.id] = r[a.id] || { id: a.id, quantity: 0, name: a.name };
r[a.id].quantity += a.quantity;
return r;
}, Object.create(null));
console.log(JSON.stringify(result));
Using forEach loop and build object with aggregated quantity count.
const convert = (arr) => {
const res = {};
arr.forEach(({ id, ...rest }) =>
res[id] ? (res[id].quantity += 1) : (res[id] = { id, ...rest })
);
return Object.values(res);
};
const arr = [
{ id: 1, name: "test1", quantity: 1 },
{ id: 2, name: "test2", quantity: 1 },
{ id: 2, name: "test3", quantity: 1 },
{ id: 3, name: "test4", quantity: 1 },
{ id: 4, name: "test5", quantity: 1 },
{ id: 5, name: "test6", quantity: 1 },
{ id: 5, name: "test7", quantity: 1 },
{ id: 6, name: "test8", quantity: 1 },
];
console.log(convert(arr));

get some parameters to selected item in typeahead bootstrap

I'm using Twitter bootstrap and I use its typeahead
I used this code :
$('#demo1').typeahead({
source:[
{ id: 1, name: 'Toronto' ,country: 'usa'},
{ id: 2, name: 'Montreal',country: 'china' },
{ id: 3, name: 'New York',country: 'usa' },
{ id: 4, name: 'Buffalo' ,country: 'china'},
{ id: 5, name: 'Boston' ,country: 'usa'},
{ id: 6, name: 'Columbus',country: 'china' },
{ id: 7, name: 'Dallas' ,country: 'italy'},
{ id: 8, name: 'Vancouver' ,country: 'turky'},
{ id: 9, name: 'Seattle' ,country: 'france'},
{ id: 10, name: 'Los Angeles' ,country: 'usa'}
],
itemSelected: displayRes
});
and this is displayRes function
function displayRes(item, val,text) {
console.log(val);
console.log(text);
$('#demo1').val('');
}
when I get in the console val : is the id of selected item & text: is the name of selected item
but how can I get the country in the function displayRes ?

Categories