I need to compare/merge 2 objects with diferent structure using Lodash.
data= [
{
"name": "EMPRESA",
"value": ""
},
{
"name": "DESIGEMPRESA",
"value": "CMIP"
},
{
"name": "UTILIZADOR",
"value": ""
},
{
"name": "CD_INDICADOR",
"value": ""
},
{
"name": "DT_INI_INDICADOR",
"value": ""
},
{
"name": "DT_INI",
"value": "2017-12-13"
},
.....
]
and
dbcolsData={
"EMPRESA": "",
"UTILIZADOR": "paulo.figueiredo",
"CD_INDICADOR": "",
"DT_INI_INDICADOR": "",
"DT_INI": "",
"DT_FIM": ""
}
The question is how i can fill the values of data with the values of dbcolsData ?
Lets say put the values of dbColsData in data
Thanks in advance
Try something like this:
_.forEach(data, function(object){
object.value = dbcolsData[object.name];
})
Use Array#map (or lodash's _.map()) to iterate the data, and get the results from dbcolsData:
var data = [{"name":"EMPRESA","value":""},{"name":"DESIGEMPRESA","value":"CMIP"},{"name":"UTILIZADOR","value":""},{"name":"CD_INDICADOR","value":""},{"name":"DT_INI_INDICADOR","value":""},{"name":"DT_INI","value":"2017-12-13"}];
var dbcolsData = {"EMPRESA":"","UTILIZADOR":"paulo.figueiredo","CD_INDICADOR":"","DT_INI_INDICADOR":"","DT_INI":"","DT_FIM":""};
var result = data.map(function(o) {
return Object.assign({ data: dbcolsData[o.name] }, o);
});
console.log(result);
Reduce data to the dbcolsData structure :
var myData = data.reduce((o, nvO) => Object.defineProperty(o, nvO.name, {value: nvO.value}), {})
->
Now you can use lodash comparison functions like _.isEqual :
_.isEqual(myData, dbcolsData)
Related
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.
My target is if the id from digital_assets and products matches then get the value of URL fro digital_assets and ProductName from products object. I'm able to traverse through the object and get the values of digital_assets and products but need some help to compare these two objects based on IDs to get the value of URL and ProductName. Below is what I've done so far.
var data = [{
"digital_assets": [{
"id": "AA001",
"url": "https://via.placeholder.com/150"
},{
"id": "AA002",
"url": "https://via.placeholder.com/150"
}]
}, {
"products": [{
"id": ["BB001", "AA001"],
"ProductName": "PROD 485"
},{
"id": ["BB002", "AA002"],
"ProductName": "PROD 555"
}]
}
];
$.each(data, function () {
var data = this;
//console.log(data);
$.each(data.digital_assets, function () {
var dAssets = this,
id = dAssets['id'];
// console.log(id);
});
$.each(data.products, function () {
var proData = this,
prod_id = proData['id'];
// console.log(prod_id);
$.each(prod_id, function () {
var arr_id = this;
console.log(arr_id);
});
});
});
Do I need to create new arrays and push the values into the new arrays? Then concat() these array to one. ? Bit lost any help will be appreciated.
Here is one way you can do this via Array.reduce, Array.includes, Object.entries and Array.forEach:
var data = [{ "digital_assets": [{ "id": "AA001", "url": "https://via.placeholder.com/150" }, { "id": "AA002", "url": "https://via.placeholder.com/150" } ] }, { "products": [{ "id": ["BB001", "AA001"], "ProductName": "PROD 485" }, { "id": ["BB002", "AA002"], "ProductName": "PROD 555" } ] } ]
const result = data.reduce((r,c) => {
Object.entries(c).forEach(([k,v]) =>
k == 'digital_assets'
? v.forEach(({id, url}) => r[id] = ({ id, url }))
: v.forEach(x => Object.keys(r).forEach(k => x.id.includes(k)
? r[k].ProductName = x.ProductName
: null))
)
return r
}, {})
console.log(Object.values(result))
You can use Array.prototype.find, Array.prototype.includes and Array.prototype.map to achieve this very gracefully.
let data = [
{
"digital_assets": [
{
"id": "AA001",
"url": "https://via.placeholder.com/150"
},
{
"id": "AA002",
"url": "https://via.placeholder.com/150"
}
]
},
{
"products": [
{
"id": ["BB001", "AA001"],
"ProductName": "PROD 485"
},
{
"id": ["BB002","AA002"],
"ProductName": "PROD 555"
}
]
}
];
// Find the 'digital_assets' array
let assets = data.find(d => d['digital_assets'])['digital_assets'];
// Find the 'products' array
let products = data.find(d => d['products'])['products'];
// Return an array of composed asset objects
let details = assets.map(a => {
return {
id : a.id,
url : a.url
name : products.find(p => p.id.includes(a.id)).ProductName
};
});
console.log(details);
changed answer to fit your needs:
var data = [
{
"digital_assets": [
{
"id": "AA001",
"url": "https://via.placeholder.com/150"
},
{
"id": "AA002",
"url": "https://via.placeholder.com/150"
}
]
},
{
"products": [
{
"id": ["BB001", "AA001"],
"ProductName": "PROD 485"
},
{
"id": ["BB002","AA002"],
"ProductName": "PROD 555"
}
]
}
]
let matchingIds = [];
let data_assetsObject = data.find(element => {
return Object.keys(element).includes("digital_assets")
})
let productsObject = data.find(element => {
return Object.keys(element).includes("products")
})
data_assetsObject["digital_assets"].forEach(da => {
productsObject["products"].forEach(product => {
if (product.id.includes(da.id)){
matchingIds.push({
url: da.url,
productName: product.ProductName
})
}
})
})
console.log(matchingIds);
working fiddle: https://jsfiddle.net/z2ak1fvs/3/
Hope that helped. If you dont want to use a new array, you could also store the respective data within the element you are looping through.
Edit:
I think i know why i got downvoted. My example works by making data an object, not an array. changed the snippet to show this more clearly.
Why is data an array anyway? Is there any reason for this or can you just transform it to an object?
Edit nr2:
changed the code to meet the expectations, as i understood them according to your comments. it now uses your data structure and no matter whats in data, you can now search for the objects containing the digital_assets / products property.
cheers
https://jsfiddle.net/2b1zutvx/
using map.
var myobj = data[0].digital_assets.map(function(x) {
return {
id: x.id,
url: x.url,
ProductName: data[1].products.filter(f => f.id.indexOf(x.id) > -1).map(m => m.ProductName)
};
});
I have an array of objects that i need to convert to a single object.
ex:need to convert
var data=[
{
"name": "EMPRESA",
"value": "CMIP"
},
{
"name": "DSP_DIRECAO",
"value": "CMIP#040#1900-01-01"
},
{
"name": "DSP_DEPT",
"value": "CMIP#040#1900-01-01#42#1900-01-01"
},
...
]
to
{
"EMPRESA": "CLCA",
"DSP_DIRECAO": "CLCA#100#1900-01-01",
"DSP_DEPT": "CLCA#100#1900-01-01#100#1900-01-01",
...
}
Turn data[x][name] to propertie and data[x][value] to atribute value
Thanks
Doesn't use LoDash, but a straight forward reduce()
var obj = data.reduce( (a,b) => {
return a[b.name] = b.value, a;
}, {});
var data=[
{
"name": "EMPRESA",
"value": "CMIP"
},
{
"name": "DSP_DIRECAO",
"value": "CMIP#040#1900-01-01"
},
{
"name": "DSP_DEPT",
"value": "CMIP#040#1900-01-01#42#1900-01-01"
}
]
var obj = data.reduce( (a,b) => {
return a[b.name] = b.value, a;
}, {});
console.log(obj);
Doing the same in LoDash would be something like
var obj = _.transform(data, (a,b) => {
return a[b.name] = b.value, a;
},{});
On lodash 4.15,
_.chain(data).keyBy("name").mapValues("value").value()
On lodash 3.10,
_.chain(data).indexBy("name").mapValues("value").value()
var newObj = {}
var data = [{
"name": "EMPRESA",
"value": "CMIP"
}, {
"name": "DSP_DIRECAO",
"value": "CMIP#040#1900-01-01"
}, {
"name": "DSP_DEPT",
"value": "CMIP#040#1900-01-01#42#1900-01-01"
}]
data.forEach(function(d) {
newObj[d.name] = d.value
})
Sorry if this has been asked before. I have the JSON structure like:
{"data":[
{"Date":"03/04/2016","Key":"A","Values":"123"},
{"Date":"04/04/2016","Key":"A","Values":"456"},
{"Date":"03/04/2016","Key":"B","Values":"789"},
{"Date":"04/04/2016","Key":"B","Values":"012"}
]}
I want to change this to a different format which is basically grouped by Key and combines rest of the field in Values
{"Result":[
{
"Key":"A"
"Values":[["03/04/2016","123"], ["04/04/2016","456"]]
},
{"Key":"B"
"Values":[["03/04/2016","789"]},["04/04/2016","012"]]
}
]}
I want to do this javascript/html
You could iterate and build a new object if not exist.
var object = { "data": [{ "Date": "03/04/2016", "Key": "A", "Values": "123" }, { "Date": "04/04/2016", "Key": "A", "Values": "456" }, { "Date": "03/04/2016", "Key": "B", "Values": "789" }, { "Date": "04/04/2016", "Key": "B", "Values": "012" }], result: [] };
object.data.forEach(function (a) {
if (!this[a.Key]) {
this[a.Key] = { Key: a.Key, Values: [] };
object.result.push(this[a.Key]);
}
this[a.Key].Values.push([a.Date, a.Values]);
}, Object.create(null));
console.log(object);
I think this can be a better answer (but Nina's answer is the match for your problem terms) if items of data array have different properties and you don't want to change input data.
var raw = {"data":[
{"Date":"03/04/2016","Key":"A","Values":"123"},
{"Date":"04/04/2016","Key":"A","Values":"456"},
{"Date":"03/04/2016","Key":"B","Values":"789"},
{"Date":"04/04/2016","Key":"B","Values":"012"}
]};
var result = new Map;
raw.data.forEach(entry => {
var key = entry.Key;
if (this[key])
return this[key].push(getClonedData(entry));
this[key] = [getClonedData(entry)];
result.set(key, {
Key: key,
Values: this[key]
})
}, Object.create(null));
var filtered = {
result: [...result.values()]
}
console.log(filtered);
function getClonedData(entry) {
data = Object.assign({}, entry);
delete data.Key;
return data;
}
I have the following Json
var myjson = [{
"files": [
{
"domain": "d",
"units": [
{
"key": "key1",
"type": "2"
},
{
"key": "key2",
"type": "2"
},
{
"key": "key3",
"type": "2"
}]
},
{
"domain": "d1",
"units": [
{
"key": "key11",
"type": "2"
},
{
"key": "key12",
"type": "2"
},
{
"key": "key13",
"type": "2"
}]
}]
},
{
"files": [
{
"domain": "d",
"units": [
{
......
I want to create an new array from this Json array. The length of array will be the number of "units" in this Json object.
So I need to extract "units" and add some data from parent objects.
units: [{
domain: "",
type: "",
key: ""
}, {
domain: "",
type: "",
key: ""
},
{
domain: "",
type: "",
key: ""
}
....
];
I guess i can probably do something like this:
var res = [];
myjson.forEach(function(row) {
row.files.forEach(function(tfile) {
tfile.units.forEach(function(unit) {
var testEntity = {
domain: tfile.domain,
type : unit.type,
key: unit.key
};
res.push(testEntity);
});
});
});
But it is difficult to read and looks not so good. I was thinking to do something like :
var RESULT = myjson.map(function(row) {
return row.files.map(function(tfile) {
return tfile.units.map(function(unit) {
return {
domain: tfile.domain,
type : unit.type,
key: unit.key
};
});
});
});
But This doesn't work and looks not better . Is there any way to do so it works, maybe in more declarative way. hoped Ramda.js could help.
It there any good approach in general to get data from any Nested json in readable way?
Implementing something like:
nestedjson.findAllOnLastlevel(function(item){
return {
key : item.key,
type: type.key,
domain : item.parent.domain}
});
Or somehow flatten this json so all properties from all parents object are moved to leafs children. myjson.flatten("files.units")
jsbin http://jsbin.com/hiqatutino/edit?css,js,console
Many thanks
The function you can use here is Ramda's R.chain function rather than R.map. You can think of R.chain as a way of mapping over a list with a function that returns another list and then flattens the resulting list of lists together.
// get a list of all files
const listOfFiles =
R.chain(R.prop('files'), myjson)
// a function that we can use to add the domain to each unit
const unitsWithDomain =
(domain, units) => R.map(R.assoc('domain', domain), units)
// take the list of files and add the domain to each of its units
const result =
R.chain(file => unitsWithDomain(file.domain, file.units), listOfFiles)
If you wanted to take it a step further then you could also use R.pipeK which helps with composing functions together which behave like R.chain between each of the given functions.
// this creates a function that accepts the `myjson` list
// then passes the list of files to the second function
// returning the list of units for each file with the domain attached
const process = pipeK(prop('files'),
f => map(assoc('domain', f.domain), f.units))
// giving the `myjson` object produces the same result as above
process(myjson)
Pure JS is very sufficient to produce the result in simple one liners. I wouldn't touch any library just for this job. I have two ways to do it here. First one is a chain of reduce.reduce.map and second one is a chain of reduce.map.map. Here is the code;
var myjson = [{"files":[{"domain":"d","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"d1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]},{"files":[{"domain":"e","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"e1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]}],
units = myjson.reduce((p,c) => c.files.reduce((f,s) => f.concat(s.units.map(e => (e.domain = s.domain,e))) ,p) ,[]);
units2 = myjson.reduce((p,c) => p.concat(...c.files.map(f => f.units.map(e => (e.domain = f.domain,e)))) ,[]);
console.log(units);
console.log(units2);
For ES5 compatibility i would suggest the reduce.reduce.map chain since there is no need for a spread operator. And replace the arrow functions with their conventional counterparts like the one below;
var myjson = [{"files":[{"domain":"d","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"d1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]},{"files":[{"domain":"e","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"e1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]}],
units = myjson.reduce(function(p,c) {
return c.files.reduce(function(f,s) {
return f.concat(s.units.map(function(e){
e.domain = s.domain;
return e;
}));
},p);
},[]);
console.log(units);
Something like this should work. .reduce is a good one for these kind of situations.
const allUnits = myjson.reduce((acc, anonObj) => {
const units = anonObj.files.map(fileObj => {
return fileObj.units.map(unit => {
return {...unit, domain: fileObj.domain})
})
return [...acc, ...units]
}, [])
Note that this relies on both array spreading and object spreading, which are ES6 features not supported by every platform.
If you can't use ES6, here is an ES5 implementation. Not as pretty, but does the same thing:
var allUnits = myjson.reduce(function (acc, anonObj) {
const units = anonObj.files.map(function(fileObj) {
// for each fileObject, return an array of processed unit objects
// with domain property added from fileObj
return fileObj.units.map(function(unit) {
return {
key: unit.key,
type: unit.type,
domain: fileObj.domain
}
})
})
// for each file array, add unit objects from that array to accumulator array
return acc.concat(units)
}, [])
Try this
var myjson = [{
"files": [{
"domain": "d",
"units": [{
"key": "key1",
"type": "2"
}, {
"key": "key2",
"type": "2"
}, {
"key": "key3",
"type": "2"
}]
},
{
"domain": "d1",
"units": [{
"key": "key11",
"type": "2"
}, {
"key": "key12",
"type": "2"
}, {
"key": "key13",
"type": "2"
}]
}
]
}];
//first filter out properties exluding units
var result = [];
myjson.forEach(function(obj){
obj.files.forEach(function(obj2){
result = result.concat(obj2.units.map(function(unit){
unit.domain = obj2.domain;
return unit;
}));
});
});
console.log(result);