Sacrates
Sacrates

Reputation: 23

How do I link a primary data set to a secondary data set with javascript?

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

Answers (3)

Here is a simpler solution to your problem.

ES6

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

ES5

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

Blauharley
Blauharley

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

gaetanoM
gaetanoM

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

Related Questions