3

Sorry if the json is not perfect, i was trying to type it into the Stackoverflow window... Anyway, you can see from below that I want to take all of the separate objects in the array and merge them into the first array that has the matching url. Once they are merged all of the others need to get removed from the array.

var myArray = [
{ 
 id: '123',
 url: 'http://foo.com/1.jpg',
 size: 7,
 qty: 1
},
{
 id: '345',
 url: 'http://foo.com/5.jpg',
 color: 'blue',
 qty: 5
},
{
 id: '678',
 url: 'http://foo.com/1.jpg',
 size: 8,
 qty: 4
}];

I need to make this array turn into... Below you can see that the objects that had matching url now have been moved into the first matched objects 'variations' key. They no longer appear separate after that. They are essentially all matched together and merged into the same object.

var myArray = [{ 
 id: '123',
 url: 'http://foo.com/1.jpg',
 variations:[
     {
       id : '123'
       size : 7,
       qty: 1
     }, 
     {
       id : '678'
       size : 8,
       qty: 4
     }],
{
 id: '345',
 url: 'http://foo.com/5.jpg',
 color: 'blue',
 qty: 5
}];

So far I have something like this: But this is just work in progress. Having trouble bringing this to the finish line.

myArray.forEach(function(product, index){
  var sizeVariations = [];
  var currentSearch = product.url;
  var filteredArray = processedProducts.filter(function( obj ) {
    return obj.primary_image === currentSearch;
  });

  if(filteredArray){
    filteredArray.forEach(function(data, index){
      sizeVariations.push({
        id : data.id,
        size : data.size,
        quantity : data.qty
      });
    });
  }
});
3
  • 1
    What have you tried? What do you need help with? See How to create a minimal, complete and verifiable example. Commented Mar 16, 2017 at 0:34
  • I really wouldn't recommend creating such a fragmented data structure (ie some entries with variations and some without). Also, how do you decide which id lives outside variations for the merged entries? Commented Mar 16, 2017 at 0:42
  • Basically if they have matching url value then I need all of the info to be in the same object Commented Mar 16, 2017 at 0:43

4 Answers 4

1

You can do something similar to this; I am not keeping the id at the top level since it looks like a duplication of data.

var myArray = [
{ 
 id: '123',
 url: 'http://foo.com/1.jpg',
 size: 7,
 qty: 1
},
{
 id: '345',
 url: 'http://foo.com/5.jpg',
 color: 'blue',
 qty: 5
},
{
 id: '678',
 url: 'http://foo.com/1.jpg',
 size: 8,
 qty: 4
}];

function mergeObjects(arr)
{
  var resultArray = [];
  var urls = [];
  for(var item in arr)
  {
    var itemIndex = urls.indexOf(arr[item].url);
    if(itemIndex == -1)
    {
      urls.push(arr[item].url);
      var obj = {};
      obj.url = arr[item].url;
      obj.variations = [];
      var variationData = {};
      variationData.id = arr[item].id;
      if(arr[item].size !== undefined)
      {
        variationData.size = arr[item].size;
      }
      if(arr[item].qty !== undefined)
      {
        variationData.qty = arr[item].qty;
      }
      if(arr[item].color !== undefined)
      {
        variationData.color = arr[item].color;
      }
     
      obj.variations.push(variationData);
      resultArray.push(obj);
    }
    else
    {
      var variationData = {};
      variationData.id = arr[item].id;
      if(arr[item].size !== undefined)
      {
        variationData.size = arr[item].size;
      }
      if(arr[item].qty !== undefined)
      {
        variationData.qty = arr[item].qty;
      }
      if(arr[item].color !== undefined)
      {
        variationData.color = arr[item].color;
      }
      resultArray[itemIndex].variations.push(variationData)
    }
    
  }
  return resultArray;
}

console.log(mergeObjects(myArray));

Sign up to request clarification or add additional context in comments.

2 Comments

This is doing exactly what I need . I am already modifying it to suit my needs. Thx
Those two phrases look like a contradiction to me :P
0

I think you can try to gather all the urls in an object first so that you can guarantee uniqueness and then convert it to an array, something like this,

function Merge(arr) {
    var obj = {};

    for (var elem of arr) {
        if (obj[elem.url] == undefined) {
            obj[elem.url] = {
                id: elem.id,
                variations: [],
                url: elem.url
            };
        }

        obj[elem.url].variations.push(elem);
        delete elem.url;
    }

    var ans = [];
    for (var elem in obj) {
        var tmp = {
            id: obj[elem].id,
            url: elem
        };
        if(obj[elem].variations.length > 1) 
            tmp.variations = obj[elem].variations;
        else {
            tmp.color = obj[elem].variations[0].color;
            tmp.qty = obj[elem].variations[0].qty;
        }
        ans.push(tmp);
    }

    return ans;
}

Comments

0

I feel like a much better data structure would be one keyed by url.

const myArray = [{"id":"123","url":"http://foo.com/1.jpg","size":7,"qty":1},{"id":"345","url":"http://foo.com/5.jpg","color":"blue","qty":5},{"id":"678","url":"http://foo.com/1.jpg","size":8,"qty":4}]

const urlMap = myArray.reduce((byUrl, entry) => {
  const entryWithoutUrl = Object.assign({}, entry)
  delete entryWithoutUrl.url

  if (Array.isArray(byUrl[entry.url])) {
    byUrl[entry.url].push(entryWithoutUrl)
  } else {
    byUrl[entry.url] = [entryWithoutUrl]
  }
  return byUrl
}, Object.create(null))

const newArray = Object.keys(urlMap).map(url => ({
  url: url,
  variations: urlMap[url]
}))

console.info(newArray)

Comments

0

In this example I have broken the problem down into two smaller problems for efficiency of not having to iterate through the array to check if a url already exists, then once everything is grouped by the url, we convert the resulting object back to an array with each key as an item in the array.

if you use functional programming you could compose these functions together

compose(objectToArray, sortByUnique)('url', myArray)

var myArray = [
  { id: '123', url: 'http://foo.com/1.jpg', qty: 1, size: 7 },
  { id: '345', url: 'http://foo.com/5.jpg', qty: 5, color: 'blue' },
  { id: '678', url: 'http://foo.com/1.jpg', qty: 4, size: 8 },
  { id: '69',  url: 'http://foo.com/1.jpg', qty: 4, size: 8 }
]

function sortByUnique(unique, array) {
  // group array by unique key into an object
  return array.reduce((acc, x) => {
    let key = x[unique]
    delete x[unique]
    if (acc[key]) {
      if (!acc[key].variations) {
        let old = acc[key]
        acc[key] = {
          variations: [old, x]
        }
      }
      else {
        acc[key].variations.push(x)
      }
    }
    else {
      acc[key] = x
    }
    return acc
  }, {})
}

function objectToArray(obj) {
  return Object.keys(obj).map(
    k => Object.assign(
      { url: k },
      obj[k]
    ))
}

console.log(
  objectToArray(sortByUnique('url', myArray))
)

4 Comments

What happens if the url is grouped inside of array...? { url : ['foo.com/1.jpg'] }
that was not in the example so it will break the above code.
Yes, i know, i apologize, but im wondering if you can demonstrate how it would work with array.
It would need to be fully reworked as it is using the singular url as the unique key for the grouping, unless it was just a single element in the url array ['goo.gl/something'], however, you would also lose the re-usability of the code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.