Accessing msg.payload Object of Objects with dynamic inner object names

Hello everyone,

I have the following msg.payload object output:
image
where in the future, there will be numerous objects inside (not just 1063960).

I would like to iterate across the objects and access the ID field in each to check for a match to an ID I want. However, the problem is that the object name "1063960" is a placeholder here, and in the future, I will be making a change to the code that will make this number random, so I won't be able to predict it and use the simple:

 if (msg.payload["1063960"].ID == "1063960") 

So, my questions is: is there some kind of symbol that I can place in this if statement instead of ["1063960"] to indicate msg.payload["any"] and have node red iterate through the inner objects and check their ID field for the match?

I found the following way of doing what I want through a previous question in the forum here;

let values = Object.values(msg.payload);

var i;
for (i = 0; i < values.length; i++) {
  if (values[i].ID == "1063960")
{
    global.gender = values[i].Gender
    msg.payload = global.gender;
    return msg; 
}
}

But I am curious to see if there is a way to just say "any" and skip over a field in the msg.payload path as that would be great to learn.

Thank you for the help in advance!

Note: I am also aware of the split node, and have managed to achieve my goal using it as well, but I am just wondering about the possibility of using the msg.payload syntax when there is a part we don't know

You can simply walk the object properties. Here is one way:

Object.keys(msg.payload).forEach( key => {
    if ( msg.payload[key].id === '1063960' ) {
        ....
    }
})
1 Like

Oh thank you!
That seems like it will do exactly what I need, but for some reason I am getting the error
""TypeError: Cannot read property 'ID' of undefined""

This is the code in my function now:

Object.keys(msg.payload).forEach( key => {
    if (msg.payload[key].ID == "1063960" ) {
        global.gender = msg.payload[key].Gender
        msg.payload = global.gender;
        return msg; 
    }
})

And the msg.payload going into it was:
image

Add a node.warn(Object.keys(msg.payload)) statement above the forEach line to see what you are actually getting there.

1 Like

I placed that as instructed and received this:
image

Then, I placed a node.warn(msg.payload[key]) right before the if and received these 2 outputs:
image

After that comes the error

That way the next iteration has payload which does not have any ID property

2 Likes

That is what I thought, because msg.payload is being overwritten, but there is also a return msg there which means that it should have returned immediately following inspecting the first element, so it should never have got to the second element.

1 Like

NO.You can't break the forEach

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

2 Likes

Oh you are right, it is a forEach not a for in. I was concentrating on what was inside instead of what was doing the iteration.
So yes, you are correct, it is the fact that msg.payload is being overwritten that is the problem.

1 Like

Thank you all so much for the help!!
I replaced the forEach with a for in as suggested and it seems to be working perfectly now as far as I can tell. I will leave the final solution here in case this is needed by someone in the future:

for (var key in msg.payload){
    if (msg.payload[key].ID == "1063960" ) {
        global.gender = msg.payload[key].Gender
        msg.payload = global.gender;
        return msg; 
    }
}```

So you are looking for single match and send out the value of Gender property of that found object.

var needle = "1234"
var o = Object.keys(msg.payload).find(e => msg.payload[e].ID == needle)
msg.payload = msg.payload[o].Gender
return msg;

But if not found

var needle = 1234
var o = Object.keys(msg.payload).find(e => msg.payload[e].ID == needle)

msg.payload = o ? msg.payload[o].Gender : "Not found" // may be undefined if Gender propery does not exist

return msg;
1 Like

Yes exactly, thank you for the alternative method, this also seems to work great! (is there a way to mark 2 answers as the solution to a thread?)

I'm wondering what the difference between the one you first posted (using e => e) and the one here with msg.payload? they both seemed to work for me

I was wrong on that, I got result but false positive and didn't check.
As the object name and ID are same (don't know is this always the case) the result is there but you wanted to check the ID property of every possible object (until first match)

1 Like

Oh that makes sense, thank you! I was confused because I was still getting the correct output despite trying an ID different than the name, but I just tried again and it gave the wrong answer, you're right; I must have done something differently the first time.

One more thing, please: msg.payload = o ? msg.payload[o].Gender : "Not found" is meant to make the value "Not found" if it was undefined, right? because I am still receiving undefined output even after deleting the "Gender" field from the object :thinking: (It doesn't really matter to me as I have a "default" in the rest of my code, but just curious of the new syntax, sorry for the trouble!)
This is the object where there is no Gender:
image

Array.find() does return found thing or undefined if nothing found.

So if the o is undefined, the msg.payload will be "Not found". In case of Gender property is missing, but the o is there, the output message payload will be undefined because of Gender does not exist.
You can make another safety check to prevent such case.

1 Like

Ah, now it is all clear, thank you for the help :pray:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.