Change an array in a function

Currently i change my array records by using the array number 0-xxxx or a variable that contains this number... (see example below).
Problem is that the record that i want to change not always has the same number..

questions

  1. is it possible to change a record in array not based on a number but for example based on another unique item in the array, like "XXXXX1"
  2. is it possible to change one attribute in a record of an array, or do i have to read the whole record and then update the whole record...

example

msg.modqueue[0] =  {
                            "service": msg.service,
                            "service_status" : msg.service_status,
                            "paralel":msg.paralel,
                            "time": msg.mytime,
                            "st_info": msg.st_info,
                            "st_debug": msg.st_debug,
                            "mresult": msg.mresult,
                            "mactive": msg.mactive
                            };

I'm not 100% sure what you mean here.

Yes, you can do, for example, msg.modqueue[0].service = msg.service

Ok, thanks for 2, learned again!

With question one i was looking for a method of getting an record in an array without using the [number] but use another element.

I solved this by using a little bit of code, dont know if this is the right way to do it.

I have for example to change a record where naam == jan

var mod=[],ifound;

mod = [{"naam":"peter", "age":5 },{"naam": "jan", "age":5 },{"naam": "klaas", "age":5 },{"naam": "pieter", "age":5 },{"naam": "miep", "age":5}];
izoek = 'jan';

msg.ifound = -1;
msg.mod=mod;

    for (i = 0; i < mod.length; i++)
        {
        test=mod[i].naam;
        if(test===izoek) 
            {
            msg.ifound=i;
            msg.test=test;
            }
        }
return msg;

I have for example to change a record where naam == jan

But you are not changing anything here ?

Have a look at the array .filter() function, that will do what you want.

Well as it still not very clear what you want to do with your function, we can make arbitrary examples how things can be done.

//array of objects
let mod = [{"naam":"peter", "age":5 },{"naam": "jan", "age":5 },{"naam": "klaas", "age":5 },{"naam": "pieter", "age":5 },{"naam": "miep", "age":5}];

//name to search
let targetname = "jan"

//output does not exist yet cos we don't know can we find the name
let output = null

// lets modify the array by using .map method
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
mod = mod.map(obj => {
   // every object in array explored to find the target
    // if naam propert has value we are searching
   if(obj.naam === targetname){
       obj.age ++ //lets make that person one year older (change).
       output = obj // as we have success of, lets put that object to output variable 
   }
   return obj 
})

//lets write changed array to debug tab to see what just happened
node.warn('changed array: '+JSON.stringify(mod))

//as mod array is modified, you may wan to store it in context but that's another story
//context.set("mod",mod)

// send message if we have found person in array and made changes
if(output !== null){
    //send changed object
    msg.payload = output
    // or send whole modified arrray
    //msg.payload = mod
    return msg;
}

thanks all, i learned a lot!
I am going to play and test with the different kind of solutions..

To explain what i need it for:
I have a array; in that array are all the (sub)modules that must be executed paralel or serieel to accomplish a task, it also contains parameters for that submodule. Sometimes the executionplan changes during the execution, then i must change a record in the array, so that the submodule is executed differently or not at all..

The submodules (records in a array) are not always on the same place in the array, for example: ARRAY or ARRAY[7], where x=[0-999] . Thats why i asked if a record i a array can be changed by name and not by adressing the array id (number.)
I believe javascript cant handle arrays other then by number so i tried to make a script that searches the array for a string value , stores the recordnumber et voila.

I am curious if this is the easiest way to do it.

ifound = -1;        //nodig om te kijken waar in de array de oscmd module zit
function Zoek_id_modqueue(izoek) 
    {for (i = 0; i < msg.modqueue.length; i++)   if(msg.modqueue[i].naam==izoek)  ifound=i;return ifound;}

ifound= Zoek_id_modqueue('Herstarten van de domoticz service');  
        if(ifound !== -1)  msg.modqueue[ifound] =  {"mactive": true};     

Like most languages, array's can only be directly referenced by position. To reference an array by part of each array entry's content, you need to use the filter function as mentioned - you can do it yourself manually of course but the filter function should be heavily optimised. You specify a called function as part of the filter function and that inner function is called for each element of the array. All you need to do is return true or false. All of the array records that return true will be returned by the filter function. In your case, you will just want a single record to be returned.

Yes, indeed. I want the position back from the record in the aray where the string was found so that i can update that specific record in the array for further usage..

i take a look at the filter function!

Unless I am understanding the "problem" incorrectly: this is a breeze for jsonata

1 Like

I think that you still need to use the JSONata filter function don't you? This is equivalent to the JavaScript one I think.

Can you further specify what you're looking for here?

If I understand it well you're following the next set of steps:

  1. have an array with objects inside
  2. search through the list for an object that matches a condition
  3. find the position of that object
  4. query the array through index, eg msg.modqueue[i]
  5. update the object through msg.modqueue[i] = ... or msg.modqueue[i].property = ...

Is this a correct representation of what you're doing?

yes, thats what i meant..

I have a working solution at the moment, but with java...
Dont know if there is a better way..
I still need some time to play with the filter option and i dont have any experience with jsonata

For now this is a way to do it..

msg.modqueue =  [
            {"service": "Check server", "service_status" : false,"paralel":false, "time": null, "st_info":true, "st_debug":false, "mresult":null,"mactive":true},
            {"service": "Database", "service_status" : false,"paralel":true, "time": null,"st_info":true, "st_debug":true,"mresult":null,"mactive":true},
            {"service": "Notificatie", "service_status" : false,"paralel":true, "time": null,"st_info":true, "st_debug":true,"mresult":null,"mactive":true},
            {"service": "OS command", "service_status" : false,"paralel":false, "time": null,"st_info":true, "st_debug":true,"mresult":null,"mactive":false}
            ];

ifound = -1;        //nodig om te kijken waar in de array de mqtt out module zit
function Zoek_id_modqueue(izoek) 
    {
    for (i = 0; i < msg.modqueue.length; i++)   
        {
        if(msg.modqueue[i].service==izoek)  // GEBRUIK T JUISTE ZOEK ATTRIBUUT HIER !!!!!
            {
            ifound=i;
            return ifound;
            }
        }
    }

ifound= Zoek_id_modqueue('Database');  

if(ifound > -1)  // element op active zetten zodat OS module wordt uitgevoerd
    {
    msg.modqueue[ifound].mactive = true;
    }


return msg;

I've already given you a better answer. Using the Array filter() function, that is what it is for.

A bit tangential, but what I like to do is to take many msg objects and send them to a join node configured to manually output an array of message objects; and send that array to a function which creates a new msg object.

Just started a Telegram bot which gives me remote server info.... so fun....

Node-RED is too awesome!

Still working on it.. plan something like:

.... menu items for some stats like apache processes, apache CPU, MySQL CPU, disk space, total users, bots and members on line and that will be "just about it".... something simple. I also have /ping but it is becoming moot since can just get other info instead of "pinging it".

For those who like Javascript programming, Node-RED is just toooooo much fun.... THANK GUYS!

1 Like

i know, going to play with that too!

In summary: If your goal is to find a specific item matching a condition, use the .filter() function like TotallyInformation suggested. If your goal is to edit items in an array, use the .map() function to walk through it and be able to query each object in a way you'd like to. That includes checking for conditions. This is what HotNipi above suggested. If your goal is to find the position in an array of a specific item, for whatever reason you might need it (map is preferred for editing an array like your situation includes), use .findIndex().



1 Like

thanks, i will try the filter. I need to edit/change a record in array and i dont know what the id is offthe aaray so i have to serach each record in the array, when mach then change..

I am going to try the filter first

Please read the link for .map(), and the example by @hotNipi above. You don't need to know the index of item in the array in order to change it if you use map(). If you use filter() you will get the element you're trying to edit as output instead, but you'll still have to edit it and push it back in the array at the position you're attempting. .map() is by far the best option you have here, and gives the cleanest code too.

Hi all,

I try to learn a lot, so i tried all options.
My own java loop already worked, so i was looking for an better, shorter alternative.

I hoped for somethings like this (i know this does not exist, it is pseudo..).

pseudo code

modqueue =  [
            {"service": "Check server", "service_status" : false,"paralel":false, "time": null, "st_info":true, "st_debug":false, "mresult":null,"mactive":true},
            {"service": "Database", "service_status" : false,"paralel":true, "time": null,"st_info":true, "st_debug":true,"mresult":null,"mactive":false},
            {"service": "Notificatie", "service_status" : false,"paralel":true, "time": null,"st_info":true, "st_debug":true,"mresult":null,"mactive":true},
            {"service": "OS command", "service_status" : false,"paralel":false, "time": null,"st_info":true, "st_debug":true,"mresult":null,"mactive":false}
            ];
a= modqueue.searchfunction ("service" === "Database")
modqueue[a].service = true;

Option 1. my own java (see earlier script above) WORKS
Option 2 map option WORKS (BETTER THEN MY SOLUTION)
Option 3 findindex --> could not get this to work with my array with more elements in a record
Option 3 filter --> could not get this to work with my array with more elements in a record

option 1 see above

option 2 map

modqueue =  [
            {"service": "Check server", "service_status" : false,"paralel":false, "time": null, "st_info":true, "st_debug":false, "mresult":null,"mactive":true},
            {"service": "Database", "service_status" : false,"paralel":true, "time": null,"st_info":true, "st_debug":true,"mresult":null,"mactive":false},
            {"service": "Notificatie", "service_status" : false,"paralel":true, "time": null,"st_info":true, "st_debug":true,"mresult":null,"mactive":true},
            {"service": "OS command", "service_status" : false,"paralel":false, "time": null,"st_info":true, "st_debug":true,"mresult":null,"mactive":false}
            ];

let izoek = "Database"
let output = null

modqueue = modqueue.map(obj => {
   if(obj.service === izoek)   {obj.active = true;output = obj}
   return obj 
})

node.warn('changed array: '+JSON.stringify(modqueue))

if(output !== null)
    {msg.payload = output;return msg;}