I'm trying to combine 2 object array in javascript/jquery matching them by the same key (code). These object arrays are stored in 2 separate json files.
I've cut these down as the files are long
Thanks in advance if anyone can help.
Object 1:
[{
"city": "london",
"selfemployed": {
"job" :"Builder",
"code": "abc"
},
"company" : {
"job": "Shopkeeper",
"code": "def"
}
}]
Object 2:
[{
"code": "abc",
"participant": {
"firstname" : "Joe",
"lastname" : "Blogs"
}
},
{
"code": "def",
"participant": {
"firstname" : "Anna",
"lastname" : "Smith"
}
}]
Needed result:
[{
"city": "london",
"selfemployed": {
"job" :"Builder",
"code": "abc",
"participant": {
"firstname" : "Joe",
"lastname" : "Blogs"
}
},
"company" : {
"job": "Shopkeeper",
"code": "def",
"participant": {
"firstname" : "Anna",
"lastname" : "Smith"
}
}
}]
One of my issues is that I'm unable to return the object from the .json files
var file1 = 'url/file1.json';
var file1 = 'url/file2.json';
const joinJson = (file1, file2) => {
$.getJSON(file, function(data1) {
return data1;
});
$.getJSON(file2, function(data2) {
return data2;
});
// do stuff with data1 and data2
}
console.log(joinJson());
You could take a Map and build new objects for the result by selecting the wanted code information for the new object.
This proposal uses rest properties of an object with babel for older user agents.
var cities = [{ city: "london", selfemployed: { job: "Builder", code: "abc" }, company: { job: "Shopkeeper", code: "def" } }],
codes = [{ code: "abc", participant: { firstname: "Joe", lastname: "Blogs" } }, { code: "def", participant: { firstname: "Anna", lastname: "Smith" } }],
codesMap = new Map(codes.map(({ code, participant }) => [code, participant])),
result = cities.map(
({ city, ...items }) =>
Object.assign({ city }, ...Object.entries(items).map(
([k, v]) => ({ [k]: Object.assign({}, v, codesMap.get(v.code)) })
))
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The problem is that you're getting the files asynchronously, and returning data in the callback of that async operation, which goes nowhere. Something like this would be better:
var file1 = 'url/file1.json';
var file1 = 'url/file2.json';
const joinJson = (file1, file2) => {
$.getJSON(file, function(data1) {
// async operation 1 complete. Start operation 2.
$.getJSON(file2, function(data2) {
// async operation 2 complete
// data1 and data2 are now available here
console.log("Data 1:", data1);
console.log("Data 2:", data2);
// This will merge the keys of both objects
// but you can replace it with custom merging logic
var merged = Object.assign(data1, data2);
console.log(merged);
});
});
}
The problem here is that you can't do something like console.log(joinJson());. You may very well need something like a Promise.
Related
I am consuming a (badly designed) API which sends the following response:
{
"0" : {
"name" : "John",
"last_name" : "Doe"
},
"1" : {
"name": "Mary",
"last_name": "Ann"
},
[...]
}
As you may have noticed, it is a large JSON object with nested objects. Since it isn't an array, i can't use .filter(). So, how can i filter this large object by a nested object property (e.g. name or last_name)?
You can make it as array using Object.values(type).flat(). Then it will make the object values as single array.
const input1 = {
"0" : {
"name" : "John",
"last_name" : "Doe"
},
"1" : {
"name": "Mary",
"last_name": "Ann"
}
}
function search(input, key) {
return Object.values(input).flat().filter(({ name }) => name === key);
}
console.log(search(input1, "John"));
let obj1 =obj1.json**
{
"stores": {
"city1": [
{
"address": null,
"firstName": null,
"lastName": null
}
]
}
}
let obj2 = obj2.json**
{
"stores": {
"city1": [
{
"address": 13, Landiling,
"firstName": Robot,
"lastName": Tom,
"phone": 12345678,
"email": test#,
"manager": tim
}
]
}
}
here is the code I am using to update obj1 values with obj2.
result = Object.keys(obj1.stores.city1[0]);
for (var i = 0; i< result.length; i++ ) {
console.log(result[i]);
console.log(JSON.stringify(obj1.stores.city1[0].result[i]));
obj1.stores.city1[0].result[i]=obj2.stores.city1[0].result[i];
}
I am able to get the child Keys from obj1, using above code, but not able to update the values back to obj1. as it showing it as 'i' is not defined or received undefined result.
I changed your code a little bit to make it run on my local machine. Here is the working code which is achieving what you are trying to achieve.
const obj1 = {
stores: {
city1: [
{
address: null,
firstName: null,
lastName: null
}
]
}
}
const obj2 = {
stores: {
city1: [
{
address: '13, Landiling',
firstName: 'Robot',
lastName: 'Tom',
phone: 12345678,
email: 'test#',
manager: 'tim'
}
]
}
}
const result = Object.keys(obj1.stores.city1[0])
console.log('Keys: ', result)
for (var i = 0; i < result.length; i++) {
console.log('Key: ', result[i])
console.log('Value:', JSON.stringify(obj1.stores.city1[0][i]))
obj1.stores.city1[0][result[i]] = obj2.stores.city1[0][result[i]]
}
console.log('object 1: ', JSON.stringify(obj1))
console.log('object 2: ', JSON.stringify(obj2))
The following line of your code:
obj1.stores.city1[0].result[i]=obj2.stores.city1[0].result[i];
Is being translated as
obj1.stores.city1[0].result.<value of i> = obj2.stores.city1[0].result.<value of i>;
You're looking for result property on the city1[0] object which doesn't exists then you are trying to access a number <value of i> property on result object (which itself is undefined). So you are trying to access undefined property of undefined object. That's why you are unable to change the obj1. I hope my answer clarifies.
You will need to know the current city key to lookup the city in the update object.
Loop over the city keys
Loop over the cities by the city key
Assign the update object at the corresponding index in the city array
Not sure if you want to copy all the properties over, but you did not have example output.
const toBeUpdated = {
"stores": {
"city1": [{
"address": null,
"firstName": null,
"lastName": null
}]
}
}
const updateInfo = {
"stores": {
"city1": [{
"address": "13, Landiling",
"firstName": "Robot",
"lastName": "Tom",
"phone": "12345678",
"email": "test#",
"manager": "tim"
}]
}
}
Object.keys(toBeUpdated.stores).forEach(cityKey => {
toBeUpdated.stores[cityKey].forEach((city, index) => {
Object.assign(city, { ...updateInfo.stores[cityKey][index] });
});
});
console.log(toBeUpdated);
.as-console-wrapper {
top: 0;
max-height: 100% !important;
}
How can we push values to an object from inside a map function and return that single object. I have string comparison condition inside the map function. I tried using Object.assign but it returns an array with multiple object inside that array. Instead of this multiple object I'm expecting a single object inside an array.
Map function
let arrayObj = arrayToTraverse.map(function(item) {
var myObj = {};
if(item.inputvalue === 'Name'){
Object.assign(myObj, {name: item.value});
} else if (item.inputvalue === 'Email'){
Object.assign(organizerInfo, {email: item.value});
} else if (item.inputvalue === 'Company'){
Object.assign(organizerInfo, {company: item.value});
}
return myObj;
});
console.log("The array object is", arrayObj)
This return the array of objects as follows
[
{
"name": "Tom"
},
{
"email": "tom#abc.com"
},
{
"company": "ABC"
}
]
But The array I'm expecting is
[
{
"name": "Tom",
"email": "tom#abc.com",
"company": "ABC"
}
]
// or
[
"returned": {
"name": "Tom",
"email": "tom#abc.com",
"company": "ABC"
}
]
An example of arrayToTraverse can be considered as following
[
{
"id": "1",
"inputvalue": "Name",
"value": "Tom",
"type": "Short Text"
},
{
"id": "2",
"inputvalue": "Email",
"value": "tom#abc.com",
"type": "Email ID"
},
{
"id": "3",
"inputvalue": "Company",
"value": "Google",
"type": "Long Text"
}
]
Simply put, you're trying to reduce an array to a single object, not map one array to another.
var arrayToTraverse = [
{inputvalue:"Name",value:"Tom"},
{inputvalue:"Email",value:"tom#abc.com"},
{inputvalue:"Company",value:"ABC"},
{inputvalue:"Foo",value:"Bar"} // wont show up
];
var valuesRequired = ["Name","Email","Company"];
var result = arrayToTraverse.reduce( (acc, item) => {
if(valuesRequired.includes(item.inputvalue))
acc[item.inputvalue.toLowerCase()] = item.value;
return acc;
}, {});
console.log(result);
Edit: Added lookup array for required fields.
i'm searching a smart way to reoganise an array by a element inside it:
In entry i've got:
[{"name": "brevet",
"country": "fr"
},{
"name": "bac",
"country": "fr"
},{
"name": "des",
"country": "ca"
},{
"name": "dep",
"country": "ca"
}{
"name": "other",,
"country": "other"}]
I want to reorganize my array by country to have this in my output:
[{
"name": "fr",
"degrees": [
{
"name": "brevet",
"country": "fr"
},{
"name": "bac",
"country": "fr"
}]
},{
"name": "ca",
"degrees": [{
"name": "des",
"country": "ca"
},{
"name": "dep",
"country": "ca"
}]
},{
"name": "other",
"degrees": [{
"name": "other",
"country": "other"
}]
}]
For this i write a dirty function, but it seems to me there is a better way but i don't see how. If someone can ligth my brain in a better way to do this i'll be helpfull
private organizeDegrees(degrees: Array<SubscriptionFieldInterface>) {
let degreesByCountry = new Array();
let storeIndex = new Array();
degrees.map(degree => {
let index = null;
storeIndex.find((element, idx) => {
if (element === degree.country) {
index = idx;
return true;
}
});
if (index === null) {
index = degreesByCountry.length;
let newEntry = {
'name': degree.country,
'degrees': new Array()
};
storeIndex.push(degree.country);
degreesByCountry.push(newEntry);
}
degreesByCountry[index].degrees.push(degree);
});
return degreesByCountry;
}
thank's
You can group the array and map the object using Object.keys:
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
var grouped = groupBy(array, "country");
var mappedArray = Object.keys(grouped).map(key => ( {name: key, degrees: grouped [key]} ));
And one more way:
arr = [ /* your array */ ];
arr = Object.values(arr.reduce((ac, el) => {
if(!ac[el.country]) ac[el.country] = {"name": el.country, "degrees": []}
ac[el.country].degrees.push(el);
return ac
}, {}))
console.log(arr) // formated
Another solution, which also handles 'id' => '#id' mapping:
const a = [{"name":"brevet","country":"fr"},{"name":"bac","country":"fr"},{"id":73,"name":"des","country":"ca"},{"name":"dep","country":"ca"},{"name":"other","country":"other"}];
const r = [...new Set(a.map(({country}) => country))] // list of unique country names
.map(c => Object.assign({name: c}, // for each country
{degrees: a.filter(x => x.country === c).map(y => Object.keys(y).includes('id') // handle 'id' => '#id' mutation
? {'#id': "/subscription_fields/" + y.id, name: y.name, country: y.country}
: y)
}))
console.log(r)
This is purely ES6, and quite terse, but possibly less readable. Also, it doesn't add the "#id": "/subscription_fields/83", which could be added as a post process:
const groupByKey = (arr, key) => [...arr.reduce((acc, deg) =>
acc.set(deg[key], {name: deg[key], degrees: [ ...(acc.get(deg[key]) || {degrees: []}).degrees, deg]})
, new Map()).values()];
console.log(groupByKey(degrees, 'country'));
You could use a hash table and collect all values in an object. For getting the result array, you need to push the object only once.
var data = [{ name: "brevet", country: "fr" }, { name: "bac", country: "fr" }, { id: 73, name: "des", country: "ca" }, { name: "dep", country: "ca" }, { name: "other", country: "other" }],
result = data.reduce(function (hash) {
return function (r, a) {
if (!hash[a.country]) {
hash[a.country] = { name: a.country, degrees: [] };
r.push(hash[a.country]);
}
hash[a.country].degrees.push({ name: a.name, country: a.country });
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
i'm trying to create a <String, Array()> map from a json object.
Imagine i got this json structure:
[
{
"userId": "123123",
"password": "fafafa",
"age": "21"
},
{
"userId": "321321",
"password": "nana123",
"age": "34"
}
]
The map i want to create would be:
key (string), value (array)
{
"userId": [
"123123",
"321321"
],
"password": [
"fafafa",
"nana123"
],
"age": [
"21",
"34"
]
}
Is it possible to do this? :/
Thanks in advance.
Demo
var json = '[{"userId" : "123123", "password": "fafafa", "age": "21"}, {"userId" : "321321", "password" : "nana123", "age" : "34"}]';
var list = JSON.parse(json);
var output = {};
for(var i=0; i<list.length; i++)
{
for(var key in list[i])
{
if(list[i].hasOwnProperty(key))
{
if(typeof output[key] == 'undefined')
{
output[key] = [];
}
output[key].push(list[i][key]);
}
}
}
document.write(JSON.stringify(output));
Outputs:
{"userId":["123123","321321"],"password":["fafafa","nana123"],"age":["21","34"]}
function mergeAttributes(arr) {
return arr.reduce(function(memo, obj) { // For each object in the input array.
Object.keys(obj).forEach(function(key) { // For each key in the object.
if (!(key in memo)) { memo[key] = []; } // Create an array the first time.
memo[key].push(obj[key]); // Add this property to the reduced object.
});
return memo;
}, {});
}
var json = '[{"userId" : "123123", "password": "fafafa", "age": "21"}, {"userId" : "321321", "password" : "nana123", "age" : "34"}]';
mergeAttributes(JSON.parse(json));
// {
// "userId": ["123123", "321321"],
// "password": ["fafafa", "nana123"],
// "age": ["21", "34"]
// }
Javascript's JSON.stringify will help you to convert any JSON compliant object model into a JSON string.