So close I can feel it, but why can't I pass these 2 tests? STILL stuck on the Record Collection

I’ve been stuck on this problem for far longer than I care to admit, it’s just really been twisting my mind. My biggest issue was figuring out how to determine whether something did or did not exist (Specifically, checking if “tracks” exists and creating the new array if it does not exist). Luckily I “figured out” that I needed to use .hasOwnProperty to do that part. Now I’m down to just failing 2 checks and it seems so simple yet I cannot see what I need to change to make EVERYTHING work. Here is my code from the challenge so far:

function updateRecords(id, prop, value) {
  
  if (value === "") {
      delete collection[id][prop];
      return collection;
  } 
  
// I also tried "if (prop)" and it didn't change anything here
  if (prop === "tracks") {
      if (collection[id].hasOwnProperty(prop) === false) {
        collection[id][prop] = [prop];
      }
    collection[id][prop].push(value);
  }
  return collection;
}

With this code, these are the only 2 points I am not passing:

After updateRecords(5439, "artist", "ABBA") , artist should be "ABBA"

After updateRecords(1245, "album", "Riptide") , album should be "Riptide"

Clearly I am not checking [prop] correctly because in the 2 points above the prop for “artist” and “album” do not exist and would need to be created, however, another point where “tracks” is missing and needs to be added first does work.

Course link: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/record-collection

What if prop is not “tracks” and value is not an empty string?

The way I understand is that if value isn’t an empty string, it will automatically pass that first if statement and run everything under the assumption that value isn’t empty since we already checked if it is empty or not.

As for the if (prop === "tracks") portion, that’s what I assumed was causing the issue I have now and I changed it to if (prop) thinking that would make it a little more “all purpose” based on boolean values tied to prop, but that didn’t change the results at all.

Your code above doesn’t do anything if the value isn’t an empty string and prop isn’t “tracks”. What is your current code?

My current code is still set as what I originally posted here:

function updateRecords(id, prop, value) {
  
  if (value === "") {
      delete collection[id][prop];
      return collection;
  } 
  

  if (prop === "tracks") {
      if (collection[id].hasOwnProperty(prop) === false) {
        collection[id][prop] = [prop];
      }
    collection[id][prop].push(value);
  }
  return collection;
}

But the issue I’m having is that it won’t create the prop if the prop doesn’t exist (i.e. tracks, album, and artist all need to be created at some point because they don’t exist for the referenced id)

I recognized from other examples that a lot of people had something like if (prop !== "tracks") but then the rest looks similar to mine, so I tried changing that to just checking is prop is not tracks and I still can’t manage to pass the first and last points. I also tried checking `if (prop !== “”) and it still passes all the same points, doesn’t change anything. The way I look at it is that with it set as:

  if (prop !== "") {
      if (collection[id].hasOwnProperty(prop) === false) {
        collection[id][prop] = [prop];
      }
    collection[id][prop].push(value);
  }

It should work equally whether the prop is tracks, artist, or album. There must be something I’m not understanding still.

Also sorry for failing to mention this, but according to this step, it is passing through if value isn’t empty:

After updateRecords(1245, "tracks", "Addicted to Love") , tracks should have "Addicted to Love" as the last element.

That’s what’s making this even more confusing, it really seems like it should be working at least with if (prop !== "") even though that would be [technically] flawed since it would allow really any parameter to work in prop.

collection[id][prop].push(value)

what if it is not an array? artist, album and those other props are all strings. Only tracks is an array.


Also, why this? Why are you creating a key in the object like "tracks": ["tracks"]

collection[id][prop] = [prop];

If you use this you can see what your code do at each step: http://pythontutor.com/javascript.html
Maybe it can helps you

I’m sorry but when I run mine through that evaluator it even shows me as passing step 1 when FCC is telling me my code won’t work for step 1 :frowning:

So there are a few different branches of logic it seems you aren’t considering:

  • If prop is NOT “tracks” and value is NOT empty, you need to do one of two things: either create the property if it doesn’t exist, or update the value of that property if it does. The statement to do both of these would be exactly the same.
  • if prop is NOT “tracks” and value IS empty, you need to remove that property from the object. Doesn’t matter whether or not it exists, simply delete the property.
  • if prop IS “tracks”, there are two branches: it depends whether or not the tracks property exists on the object.

.tracks is a different case from a simple String or Number property, it’s an array. So here are THOSE two routes:

  1. if the .tracks property does NOT exist, create an empty array.
  2. Now, in either case, you have a .tracks property. Append the value onto that .tracks.

Your code doesn’t have enough if/else branches. Can you see how to implement them?

Ok I actually went back to the code visualizer and I know what’s going on. I have no idea how to add an empty array! I have it worded incorrectly! I ran the visualizer while using

After updateRecords(5439, "tracks", "Take a Chance on Me") , tracks should have "Take a Chance on Me" as the last element.

This was the result, it’s actually using

if (collection[id].hasOwnProperty(prop) === false) {
        collection[id][prop] = [prop];
      }

image

See, the way I saw it is “If the prop entered is false (doesn’t exist) then add what was entered for “prop” as a new array, then add the value.” However, that isn’t what my code is actually doing. It’s adding the array with the prop name, then it’s adding the prop name as the first element in the array! So, I guess I just need to figure out how to properly add the array without adding the prop name as the first element.

Other than that, it really seems to me like I’m hitting all the points according to different tests in the visualizer.

Excuse my lack of details, I also forgot to mention that instead of using

if (prop === "tracks") {
      if (collection[id].hasOwnProperty(prop) === false) {
        collection[id][prop] = [prop];
      }
    collection[id][prop].push(value);
  }

I’m now using

  if (prop !== "") {
      if (collection[id].hasOwnProperty(prop) === false) {
        collection[id][prop] = [prop];
      }
    collection[id][prop].push(value);
  }
  return collection;
}

So yeah, I think you’re on the right track. Look at the line:

collection[id][prop] = [prop];

as that is where your problem is happening. ONLY in the case of a tracks property do you want to create an array, right? In fact, that is the only case where you can’t simply set

collection[id][prop] = value;

(assuming value is not blank).

But the problem is, if(collection[id].hasOwnProperty("tracks") === false) should be done as an entirely separate branch. Because, if you do that BEFORE or AFTER the case of any other property name, you’re replacing what you’ve just done. So, here’s some pseudocode:

if( the propertyName value is "tracks"){
  if( the collection[id] DOES NOT have a 'tracks" property){
     collection[id]["tracks"] = /* How do you create an EMPTY array? */
  }
  // collection[id]["tracks"] is now an array, whether it was before or not. So push the value onto it!
} else {
  // Here, we handle EVERY OTHER property name. Tracks is the only weird one.
  if (the parameter "value" is not empty){
    // We need to delete the property, so
    collection[id].delete(/*** What do you want to delete here?? ***/)
  } else {
    // Here, we have a property name and a value, so we want to either add or update that property.
    collection[id]/* How can we reference the property? And what do we want to set it to? */
  } // End of the "value" if statement
} // end of the propertyName if statement

Please note, for obvious reasons, the above code will fail miserably. It will just puke in the browser and die. It is not code. It is known as Pseudo-code. It is a means of representing the logic in human-understandable language, and gives the coder a logic skeleton to build the function in question.

So much for the logic. Now, do you remember how to create an empty array? How about looking at what you did create? You made an array with a single member when you did =[prop] – what happens if you remove the prop from that?

1 Like

to create an empty array just write collection[id][prop] = [ ] <-- this is an empty array (note that only tracks is an array, so for other props you need to do in an other way)

2 Likes

Omg I feel like such a fool…

I was too busy focusing on the fact that 2 of the ID’s don’t have “Artist” and “Album” that I completely failed to see that only tracks was an array… I was just like “They don’t have this so obviously this should work!”

That eye-opener helps greatly…

Thank you so much for the pseudo-code. That is the best way I’ve been able to understand the breakdown of processes. I still just can’t believe I missed the fact that only tracks is an array X_X

glad it helped. I learned coding in the days of mainframes and (shudder) punch cards, and one discipline i have kept is “map out pseudocode first.” Try to get the logic separate from the language.

1 Like

@snowmonkey @ieahleen I wanted to mark both of you as solved but the system doesn’t let me, but you both seriously helped me more than I thought at the time. After all this time I finally passed the record collection and can stop ripping my hair out!!!

In case you’re curious, here’s my final code:

var collection = {
    "2548": {
      "album": "Slippery When Wet",
      "artist": "Bon Jovi",
      "tracks": [ 
        "Let It Rock", 
        "You Give Love a Bad Name" 
      ]
    },
    "2468": {
      "album": "1999",
      "artist": "Prince",
      "tracks": [ 
        "1999", 
        "Little Red Corvette" 
      ]
    },
    "1245": {
      "artist": "Robert Palmer",
      "tracks": [ ]
    },
    "5439": {
      "album": "ABBA Gold"
    }
};
// Keep a copy of the collection for tests
var collectionCopy = JSON.parse(JSON.stringify(collection));

// Only change code below this line
function updateRecords(id, prop, value) {
  
  if (value === "") {
      delete collection[id][prop];
      return collection;
  } 

if (prop === "tracks") {
  if (collection[id].hasOwnProperty(prop) === false) {
        collection[id]["tracks"] = [];
        collection[id][prop].push(value);
    } else {
      collection[id][prop].push(value);
    }
} else if (prop !== "tracks" && value !== "") {
  collection[id][prop] = (value);
}




/* Attempt # which seemed best, however, with this we cannot create new objects for artist and album, we can only create the new tracks array - ALBUM and ARTIST should NOT be ARRAYS.
  if (prop === "tracks") {
      if (collection[id].hasOwnProperty(prop) === false) {
        collection[id]["tracks"] = [];
        collection[id][prop].push(value);
    } else {
      if (prop !== "") {

      }
    }
  }
*/


  /* Attempt #1 that seemed ok, ultimately will not work.
  if (prop !== "tracks") {
    collection[id][prop].push(value);
  } else if (collection[id].hasOwnProperty(prop) === false) {
        collection[id][prop] = [];
        collection[id][prop].push(value);
      }

  */
  return collection;
}

  
  


// Alter values below to test your code
updateRecords(5439,  "artist", "ABBA"); 

Since you solved the problem., I’d like to show you another cleaner version.

function updateRecords(id, prop, value) {
    const record = collectionCopy[id];

    if (!value){
        delete record[prop];
        return collectionCopy;
    }

    if (!record.hasOwnProperty("tracks") && prop === "tracks"){
        record["tracks"] = [value];
        return collectionCopy;
    }

    if (record.hasOwnProperty("tracks") && prop === "tracks"){
        record["tracks"].push(value);
        return collectionCopy;
    }

    record[prop] = value;
    return collectionCopy;
}

Always try to make your code as readable as possible.

1 Like

Could you please explain the id part to me?
I mean:

 if (!value) {
   delete record[prop];
   return collectionCopy;
}

I don’t get the id part.
I know it is supposed to return the numbers of each artist like if it was their ID, but how would I access an id?
I could access the other properties like collection['tracks'], but I don’t understand how the way you did makes the code understand the number you enter should be the id of the object.
The rest of the code is pretty clear to me, but there are values like tracks, albums, and artists, but there is no id.
Let’s say, I call the function using only one argument as the ID, the function will not return the id. At least, I haven’t found a way to do this.

Thank you :+1:

This line is referencing the inner object that has the id as key, so later you don’t need to use again, just to make it shorter to reference the properties and values

2 Likes