Reputation: 23
I am trying to extend a primary object with elements that I'll look-up from a second object.
The primary collection looks like this:
collection1 = [
{"user":"user1", "category":"cat1", "item":"item2"},
{"user":"user2", "category":"cat2", "item":"item4"}
];
The secondary collection looks like this:
collection2 = {
"dateStamp":"2016-12-23",
"details":[
{"category":"cat1", "item":"item1", "attribute":"1"},
{"category":"cat1", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item3", "attribute":"1"},
{"category":"cat2", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item4", "attribute":"3"}
]
};
I would like the final result to look like this:
collection3 = [
{"user":"user1", "category":"cat1", "item":"item2", "dt":"2016-12-23", "attribute":"2"},
{"user":"user2", "category":"cat2", "item":"item4", "dt":"2016-12-23", "attribute":"3"}
];
I was thinking to scroll-through collection1 and, for each record, look up the attribute value in collection2. However, I haven't gotten it to work; currently failing on the lookup (find) method. I'm clearly misusing it. :)
The following code fails on the commented line:
var collection1 = [
{"user":"user1", "category":"cat1", "item":"item2"},
{"user":"user2", "category":"cat2", "item":"item4"}
];
var collection2 = {
"dateStamp":"2016-12-23",
"details":[
{"category":"cat1", "item":"item1", "attribute":"1"},
{"category":"cat1", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item3", "attribute":"1"},
{"category":"cat2", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item4", "attribute":"3"}
]
};
var collection3 = [];
collection1.forEach(function(c){
c.dateStamp = collection2.dateStamp;
//c.attribute = collection2.find({"details.category":c.category, "details.item":c.item});
collection3.push(c);
});
console.log(collection3);
And I was also thinking a SQL-like "join" would be more efficient... but not sure it's possible with this data.
Can someone provide a working example and/or guidance on the most elegant way to handle this use case? Thank you!
Upvotes: 2
Views: 94
Reputation: 16412
Here is a simpler solution to your problem.
Using the Array#find
method (beware it's not supported on IE but you can use Babel or a standalone polyfill) you can find the data you need from collection2.details
.
var collection1 = [
{"user":"user1", "category":"cat1", "item":"item2"},
{"user":"user2", "category":"cat2", "item":"item4"}
];
var collection2 = {
"dateStamp":"2016-12-23",
"details":[
{"category":"cat1", "item":"item1", "attribute":"1"},
{"category":"cat1", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item3", "attribute":"1"},
{"category":"cat2", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item4", "attribute":"3"}
]
};
var collection3 = collection1.map((c) => {
c.dateStamp = collection2.dateStamp;
c.attribute = collection2.details.find((detail) => {
return detail.category === c.category && detail.item === c.item;
}).attribute;
return c;
});
console.log(collection3);
For a more conservative browser support approach, you can use this version:
var collection1 = [
{"user":"user1", "category":"cat1", "item":"item2"},
{"user":"user2", "category":"cat2", "item":"item4"}
];
var collection2 = {
"dateStamp":"2016-12-23",
"details":[
{"category":"cat1", "item":"item1", "attribute":"1"},
{"category":"cat1", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item3", "attribute":"1"},
{"category":"cat2", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item4", "attribute":"3"}
]
};
var collection3 = collection1.map(function(c) {
var detail;
c.dateStamp = collection2.dateStamp;
for (var i = 0; i < collection2.details.length; i++) {
detail = collection2.details[i];
if (detail.category === c.category && detail.item === c.item) {
c.attribute = detail.attribute;
break;
}
}
return c;
});
console.log(collection3);
You will also notice that in both versions I replaced your Array#forEach
call with an Array#map
call since it's cleaner what the intention the code is, to generate a new array from collection1
.
Upvotes: 0
Reputation: 4246
Just in time before christmas, hope this helps:
collection1 = [
{"user":"user1", "category":"cat1", "item":"item2"},
{"user":"user2", "category":"cat2", "item":"item4"}
];
collection2 = {
"dateStamp":"2016-12-23",
"details":[
{"category":"cat1", "item":"item1", "attribute":"1"},
{"category":"cat1", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item3", "attribute":"1"},
{"category":"cat2", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item4", "attribute":"3"}
]
};
function mergeObjects(obj1,obj2){
var obj3 = {};
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
return obj3;
}
function compare(obj,array){
var foundIndex = -1;
var maxCount = 0;
for(var index=0; index < array.length; index++){
var count = 0;
for(var prop in obj){
if(obj[prop] === array[index][prop]){
count++;
}
}
if(count>maxCount){
maxCount = count;
foundIndex = index;
}
}
return array[foundIndex];
}
var collection3 = [];
for(var col1=0; col1 < collection1.length; col1++){
// search in collection2['details'] for each equal collection1 element
var coll2Result = compare(collection1[col1],collection2['details']);
// build a element for collection3
var mergeObj = mergeObjects(collection1[col1], coll2Result);
mergeObj = mergeObjects(mergeObj, {dt: collection2['dateStamp']});
collection3.push(mergeObj);
}
console.log(collection3);
Upvotes: 1
Reputation: 42054
Using Array.prototype.forEach it's possible to count the number of elements in collection2.details grouped by category.
After with Array.prototype.map it's possible to produce the final result:
var collection1 = [
{"user":"user1", "category":"cat1", "item":"item2"},
{"user":"user2", "category":"cat2", "item":"item4"}
];
var collection2 = {
"dateStamp":"2016-12-23",
"details":[
{"category":"cat1", "item":"item1", "attribute":"1"},
{"category":"cat1", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item3", "attribute":"1"},
{"category":"cat2", "item":"item2", "attribute":"2"},
{"category":"cat2", "item":"item4", "attribute":"3"}
]
};
var hwc2 = {};
collection2.details.forEach(function(ele) {
hwc2[ele.category] = (hwc2[ele.category] === undefined) ? 1 : hwc2[ele.category] + 1;
});
var collection3 = collection1.map(function(val, idx) {
var retVal = val;
retVal['dt'] = collection2.dateStamp;
retVal['attribute'] = hwc2[val.category];
return retVal;
});
console.log(collection3);
Upvotes: 0