Working with an Array in a SubFlow

Hello Community,

I need help on this one. I want to create a subflow that maintains a “list” in the form of an array of objects.

I would like to let the user configure a “uniqueID” being a property such that the list will not have entries with dupliacteIDs.

My problem is in the “findEntryOnList” function mentioned below where I would like the “item.details.credentialNumber” become a variable based on the subflow’s Environment variable… and I am not able to do that.

Any suggestions how to fix this?

Below is a snap of my code in the function inside the subFlow:

//This function maintains a list of unique entries in an array
//This function will compare the incoming message's "uniqueID" property with the mainatined list
// if the "uniqueID" exists on the list -> the messages replaces the existing entry on the list
// if the "uniqueID" does not exist -> the message is added to the list

var list = context.get("list") || ; // load the list from the node's memory

//UniqueID
var prop = env.get("UniqueID");
var value = RED.util.getMessageProperty(msg,prop);
var uniqueId = value;
SubFlow Variable is a Property Name

function findEntryOnList (item){ return item.details.credentialNumber == uniqueId; } // This works!!!!

//function findEntryOnList (item){ return item[prop] == uniqueId; } // This Doesn't work :frowning:

var index1 = list.findIndex(findEntryOnList);

square bracket notation doesnt do sub property evaluation.

e.g. if prop = "payload.details.credentialNumber" then item[prop] is looking for item["payload.details.credentialNumber"];

in JSON it becomes more obvious

{
  item : { 
    "payload.details.credentialNumber" : "value" 
  }
}

try this (untested)...

var found = list.find( item => RED.util.getMessageProperty(item, prop) != null )
if(found) {
  ...
}

Thanks for the suggestion Steve.

i am not that good in JavaScripts & the 'item =>' method :slight_smile:

I've tried your suggestion but i get: ""TypeError: Cannot read property 'details' of undefined"

Not sure if this can help... if it does it would be truly appreciated!... below is the entire content of my function "in the sSbFlow":

var list = context.get("list") || []; // load the list from the node's memory

if (msg.payload =="")  // send out the list content when empty payload is rx
    {
    msg.payload = list;
    return msg;
    }

//UniqueID
var prop = env.get("UniqueID");
var uniqueId = RED.util.getMessageProperty(msg,prop); // the "credentialNumber" or card ID is what we want to be unique in our list
var found = list.find( item => RED.util.getMessageProperty(item, prop) != null )


if (msg.listControl == "add")
    {
        //if message with the same "credentialNumber" is not already the new entry to the list, then add it to the list
        if (!found) {
            list.push(msg.payload); //the push() method adds new items to the end of an array
        }  
        
        // if message with the same "credentialNumber" is already in the list, then update the old entry with a new one
         if (found) {
            list.splice(index1,1); // remove old entry
            list.push(msg.payload); // add new entry
        }
    }

if (msg.listControl == "remove")
    {
        //if message with the same "credentialNumber" is not already the new entry to the list, then add it to the list
        if (!found) {
             //do nothing
        }  
        
         // if message with the same "credentialNumber" is already in the list, then remove entry from list
         if (found) {
            list.splice(index1,1); // remove  entry
        }
    }
    
if (msg.listControl == "reset")
    {
       list=[];
    }
    

context.set("list", list); // save the list in node's memory
msg.payload = list;

return msg;

show me what is in the context
image

also, add node.warn(prop) below var prop = env.get("UniqueID"); and show me what prop contains.

My bet is the items in context do not have said prop

Hi Steve,

my context bar is in fact empty "selected the subflow node on the flow, even the function node inside the subflow, did the refresh and still it was empty in both cases"

as for the output of the node.warn(prop) command, i get the following:

"
function : (warn)
"payload.details.credentialNumber"
"

ok, change the node.warn to node.warn([list,prop]) - show me what you see in debug window when you operate it (expand all properties)

here's what I get:

image

So you are asking the find function to find payload.details.credentialNumber in object item

As you can see, the object/item has no payload property.

if you use details.credentialNumber as the UniqueId it should work

Thanks but that would break the logic of the following code, wouldn't it????

var prop = env.get("UniqueID");
var uniqueId = RED.util.getMessageProperty(msg,prop); // the "credentialNumber" or card ID is what we want to be unique in our list

P.S. I tried using "details.credentialNumber" as my SubFlow's environmental Variable, i still gt the same error:

image

Yes, but that is because what you search is different to what you store. e,g, you search msg but store msg.payload in your list (meaning the list objects do not have a payload property)

There are 2 solutions. the easiest / best is ...

Change the UniqueId to details.credentialNumber and change the 2nd line to var uniqueId = RED.util.getMessageProperty(msg.payload, prop);

Hi Steve,

i would still need to find the index of the entry matching the UniqueID on my list "to give a value to my index1 variable" otherwise my splice & push functions won't work "that's sadly what is happening now".

any suggestions?

This is why I usually use an object instead of an array. No searching, no splicing etc.

E.g...

var list = context.get("list") || {}; // load the list object 

var prop  = aUniqueKeyToItem;

//Find item
var foundItem = list[prop]

//use item
if (foundItem) {
  msg.payload = foundItem;
  return msg;
}

//Remove item
if (foundItem) {
  delete list[prop]
}

//Add item
if (!foundItem) {
  list[prop] = msg.payload;
}

This is not a complete solution, just some hints. Search the net for using an object as a lookup. It is much faster and simpler than using an array.

If you insist on sticking with an array, then you can use findIndex

Thanks Steve, i will give your suggestion a try.... the reason why i went with an array of objects because each message i receive is a nested object by itself, hence i went with arrays to make use of core nodes like split & join... but perhaps your suggestion could be simpler.

furthermore, the findIndex method is where i problem started!

Remember my initial code had:

function findEntryOnList (item){ return item.details.credentialNumber == uniqueId; } // This works!!!!
//function findEntryOnList (item){ return item[prop] == uniqueId; } // This Doesn't work :frowning:
var index1 = list.findIndex(findEntryOnList);

the "item.details.credentialNumber" was the bit troubling me and wanted it to become a variable... if you still have suggestions on a quick fix for this one i would appreciate it.

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