0

I have an array of objects, each of which pairs an entry id with a tag id. I'm trying to reorganize this so that I get an object with a single index for each unique entry_id with a corresponding list of the associated tags.

Changing this:

tags_entries = [
          {'entry_id': 1, 'tag_id': 1},
          {'entry_id': 1, 'tag_id': 2},
          {'entry_id': 2, 'tag_id': 1},
          {'entry_id': 2, 'tag_id': 3},
          {'entry_id': 3, 'tag_id': 1}
]

To This:

   entries = {         
         1:
         { 
          'tags': [1, 2]
         },
         2:
         {
          'tags': [1, 3]
         },
         3:
         {
          'tags': [1]
         }
    }

The function I have so far is below, but I'm getting this error with it: Uncaught TypeError: Cannot read property 'push' of undefined, which is coming from the line after the else

function collect_tags(tags_entries) {
    out = {};

    for (i=0; i<tags_entries.length;i++) 
    {
        out[tags_entries[i]['entry_id']] = {};

        if (!out.hasOwnProperty(tags_entries[i]['entry_id']))
        {

            out[tags_entries[i]['entry_id']]['tags'] = [];
            out[tags_entries[i]['entry_id']]['tags'] = tags_entries[i]['tag_id'];
        } 
        else 
        {
            out[tags_entries[i]['entry_id']]['tags'].push(tags_entries[i]['tag_id']);
        }
    }

    return out;

}

Can anyone help me figure out what's causing this? Thanks so much.

1
  • ['tags'] = undefined on the object in else. You aren't copying the entire object into out[#]. So in the first line of your loop this happens out[1] = {}. Nothing more. Commented Jan 20, 2015 at 22:59

2 Answers 2

0

So on each iteration, you use the line:

out[tags_entries[i]['entry_id']] = {};

Then you ask, does out have a property tags_entries[i]['entry_id'] ?

Of course it does, you just created it, it's an empty object.

Then you access the tags property of this empty object and get undefined. Then you try to call the push method of undefined and get your error.

As an alternative, if you don't need to support old versions of IE, I would suggest a functional style replacing the entire thing with Array.prototype.reduce .

Or if you just want to fix your code, maybe:

  1. Replace your if condition with out[tags_entries[i]['entry_id']]['tags']

  2. Replace this weird double assignmenet to the same address

    out[tags_entries[i]['entry_id']]['tags'] = [];

    out[tags_entries[i]['entry_id']]['tags'] = tags_entries[i]['tag_id'];

with just creating the array

out[tags_entries[i]['entry_id']]['tags'] = [];
  1. Don't have an else. Always push your value onto the array, even if you had to just create it.
Sign up to request clarification or add additional context in comments.

1 Comment

function combineBy(key){return function reduceToIndex(accum,x,i){if(!accum[x[key]]){accum[x[key]]=[];}accum[x[key]].push(x.tag_id);return accum};} var entries = tags_entries.reduce(combineBy("entry_id"),{})
0

This seems to do what you want:

tags_entries = [
          {'entry_id': 1, 'tag_id': 1},
          {'entry_id': 1, 'tag_id': 2},
          {'entry_id': 2, 'tag_id': 1},
          {'entry_id': 2, 'tag_id': 3},
          {'entry_id': 3, 'tag_id': 1}
]

entries = {}

tags_entries.forEach(function(e) {
  (entries[e.entry_id] ||
    (entries[e.entry_id] = {tags: []} )).tags.push(e.tag_id);
});

document.write(JSON.stringify(entries));

Comments

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.