Message queue node that can be indexed

What do you see if you add a warn to show the length before the push?

1 Like

It is 0.

Me suspects I am constantly re-making the array, rather than checking if it exists - as per the code in the FIFO subflow.

Thanks.
Stupid me didn't think of that.

Ok, not that easy.

:frowning:

If I replace the single push with this:

queue_array.push("Message 1");
queue_array.push("Message 2");
queue_array.push("Message 3");

I see a starting index of 0 and an ending index of 3. Which seems good.
But if I subsequently inject another message to invoke another 3 writes to the array.....
0 - 3.

So, I am either still wiping the array or something else.

This is how I modified to code:

var output = "";                        //  This is what returns the indexed value.
var i = 0;                              //  This is for steping through the lists.
//let queue_array = [];

var queue_array = flow.get("queue")     //  I'm guessing this checks if the array exists.
if (!Array.isArray(queue_array))
{
    queue_array = [];
}
//      Yeah, I am not using the `else` option here.  Becuase I don't understand it.


let index = context.get('SIZE') || 0;   //  I hope this part works.  (See below)

index = queue_array.length;             //  This should get the *length* of the array.

node.warn("Index " + index);

if (msg.topic == "CONTROL")
{
    //  Stuff to be done with  array.
    if (msg.payload == "NEXT")
    {
        //  Display next item
    } else
    if (msg.payload == "PREVIOUS")
    {
        //  Display previous item
        i = index - 1;
        output = queue_array[i];
        msg.payload = output
        return msg;
    } else
    if (msg.payload == "WIPE")
    {
        //  Delete this item
    } else
    if (msg.payload == "WIPE ALL")
    {
        //  Wire the whole array
    }
}

node.warn("saving data to array");

//queue_array.push(msg.payload);
queue_array.push("Message 1");
queue_array.push("Message 2");
queue_array.push("Message 3");

index = queue_array.length;

node.warn("Index " + index);            //  This shows me 3

context.set('pointer',index);           //  Save the value - for what ever reason.
context.set('SIZE',index);              //  This gets loaded next time (see above)
return;
//return msg;

I'll do a bit more digging/scratching.

Methinks thee is right.

So when I add the code:

var queue_array = flow.get("queue")     //  I'm guessing this checks if the array exists.
if (!Array.isArray(queue_array))
{
    queue_array = [];
}

That would only happen if it didn't exist.
(As per the FIFO flow)

That is all I can resolve as the test to see if it is an array.

The queue.pop( ) isn't covered in the link supplied about JS arrays. The only pop is for JS popup which is a popup message.

So that has thrown me a curve ball.

And as I said: I take pop as taking something off a stack/queue/what ever. and push is to put things on.
Yeah, ok. I need to learn the difference. But pop can't be a both way command - can it?

So unshift( ) is like a push but rather than putting at the end of the array, it puts it at the start. Hmmmmm......

googling " javascript array pop " should be within you by now...
but yes I see you have found unshift... push and pop work on the end of the array and unshift and shift work on the front. (and delete works anywhere)

@dceejay, yeah, I've found the commands.

The order (queueing) I put them in the array is a bit academic to me at this stage.

The problem is the detecting the existence of the array.
if (!Array.isArray(queue))
Seems to be a sticking point.

I added code so if it sets up the array, it node.warn( ) me.
I inject and it sets up the array.
Pressing it a second time, it does the same.

So to me the problem is that - but am I right?

(Remember it is all Greek to me. I simply try to follow what I see.)

Well you first should try to get it from context... which I think you are doing.....

var queue_array = flow.get("queue")     //  I'm guessing this checks if the array exists.

but then at the end you have to save it back to context... otherwise next time it won't be there...

Woo - hoo!

I think that was lucky of me as I just worked that out - I think.

I added this to the end of the block:
flow.set('queue',queue_array);

But the output I am seeing is not understandable.

Oh, after looking a bit harder, I think I get it.

I'll apply it to the other node I am actually using and see if it helps.

Hmmmmm....
Ok, I think I have one part of it working.

But now I can't wipe the array when I want to. I have accidentally saved 15 entries and can't wipe them.

I thought the command would be queue_array = []; because that was what I had before when it kept getting wiped.

This is a snip-it of the code:

    if (msg.payload == "WIPE ALL")
    {
        //  Wipe the whole array
    node.warn("Initialising array");
    queue_array = [];
    return;

This is what is telling me the array isn't being wiped.

let index = context.get('SIZE') || 0;   //  I hope this part works.  (See below)
node.warn("Index size from context " + index);
index = queue_array.length;             //  This should get the *length* of the array.
node.warn("Index size from array " + index);

I see 0 then for the second line I see 15.

So I am still missing something.

Pop is covered in the link that I gave. Just after map and before push.

You didn't write it back again so you didn't save the change.

D'oh! Yeah. Silly me.
I really must make idiots look smart.

You have some other logic issues too. As your code stands, you will never have a next will you? That's because you are adding to the queue after your other logic, I think that you need to add to it first?

True.
The idea is that things are put in the array.
As they are put in, the only one I can really use is the previous one.

But :wink:

I scroll back a few entries and what ever. I may want to go to the next entry too.

I'm working on it. Found quite a few problems with how the pointers are kept, etc.

Be Back Soon.

Ok, I'm stuck.

node.warn("Next entry " + i+1);

Doesn't work.

I get 11 if i = 1.

Is there a way - without introducing a new variable to get it to show i+1?

This flow works - as best I can tell.

The node counters are NOT zero counting which I think helps with seeing which message you are viewing.

Could you help me with a more tidy way with the variable j in the scheme of things.

That doesn't mean directly you. But more a general request for help.
Sorry the main function node still has a bit of old stuff in it.

That's the node with the j variable in it.
The node shows how many entries in the array. NOT zero counting.
So as the node shows the index number, I wanted it to also be non-zero counting.

Found a couple of spelling mistakes.

[{"id":"8e458e68.2f8d88","type":"function","z":"184dc884.7aba5f","name":"Array","func":"//\nvar output = \"\";                        //  This is what returns the indexed value.\nvar i = context.get('pointer') || 0;\nvar j = 0;\nvar queue_array = flow.get(\"queue\")     //  I'm guessing this checks if the array exists.\nif (!Array.isArray(queue_array))\n{\n    //  If not, set up array.\n    node.warn(\"Initialising array\");\n    queue_array = [];\n    flow.set('queue',queue_array);\n    node.warn(\"Array set up.\");\n}\n\nsize = queue_array.length;\n\nif (msg.topic == \"CONTROL\")\n{\n    //  Stuff to be done with  array.\n    if (msg.payload == \"NEXT\")\n    {\n        //  Display next item\n        i = i + 1;\n        j = i + 1;\n        node.warn(\"Next entry \" + j);\n        output = queue_array[i];\n        msg.payload = output;\n        context.set('pointer',i);               //  Save the value.\n        node.status(size + \" \" + j);\n        return msg;\n    } else\n    if (msg.payload == \"PREVIOUS\")\n    {\n        //  Display previous item\n        i = i - 1;\n        j = i + 1;\n        node.warn(\"Previous entry \" + j);\n        output = queue_array[i];\n        msg.payload = output;\n        context.set('pointer',i);               //  Save the value.\n        node.status(size + \" \" + j);\n        return msg;\n    } else\n    if (msg.payload == \"WIPE\")\n    {\n        //  Delete this item\n    } else\n    if (msg.payload == \"WIPE ALL\")\n    {\n        //  Wipe the whole array\n    node.warn(\"Initialising array\");\n    queue_array = [];\n    flow.set('queue',queue_array);\n    node.warn(\"Array Wiped.\");\n    return;\n    }\n}\n\nnode.warn(\"saving data to array\");\n\nqueue_array.push(msg.payload);\n\nsize = queue_array.length;\n\ncontext.set('pointer',i);               //  Save the value - for what ever reason.\n\nflow.set('queue',queue_array);\nnode.status(size + \" \" + pointer);\n\nreturn;\n","outputs":1,"noerr":0,"x":490,"y":1320,"wires":[["e09fc19c.cf203"]]},{"id":"c0ef557b.139f1","type":"template","z":"184dc884.7aba5f","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"Message {{payload}}","output":"str","x":230,"y":1280,"wires":[["8e458e68.2f8d88","fcb9dca0.971b5"]]},{"id":"e09fc19c.cf203","type":"debug","z":"184dc884.7aba5f","name":"Index result","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":650,"y":1320,"wires":[]},{"id":"c4bbdffc.81ab78","type":"inject","z":"184dc884.7aba5f","name":"Next","topic":"CONTROL","payload":"NEXT","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":240,"y":1360,"wires":[["8e458e68.2f8d88"]]},{"id":"16235d1e.a6c2db","type":"inject","z":"184dc884.7aba5f","name":"Previous","topic":"CONTROL","payload":"PREVIOUS","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":1390,"wires":[["8e458e68.2f8d88"]]},{"id":"8d565471.b8f5a","type":"inject","z":"184dc884.7aba5f","name":"Wipe All","topic":"CONTROL","payload":"WIPE ALL","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":230,"y":1470,"wires":[["8e458e68.2f8d88"]]},{"id":"bb6554dd.38b188","type":"inject","z":"184dc884.7aba5f","name":"Wipe","topic":"CONTROL","payload":"WIPE","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":240,"y":1440,"wires":[["8e458e68.2f8d88"]]},{"id":"26162964.640a16","type":"random","z":"184dc884.7aba5f","name":"Random number","low":"1","high":"10","inte":"true","property":"payload","x":200,"y":1250,"wires":[["c0ef557b.139f1"]]},{"id":"fcb9dca0.971b5","type":"debug","z":"184dc884.7aba5f","name":"History","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":500,"y":1230,"wires":[]},{"id":"638c9635.68a788","type":"inject","z":"184dc884.7aba5f","name":"Add new item to array","topic":"","payload":"blah_","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":1220,"wires":[["26162964.640a16"]]}]

And this is for the single wipe part of the function node code:

        //  Delete this item
        j = i + 1;
        node.warn("Removing item " + j + " which is " + queue_array[i]);
        queue_array.splice(i,1);
        flow.set('queue', queue_array);
        return;

All seems to work as I want.

(Just copy/paste this in the code at the delete this item part is. Which as posted is basically empty.)

Could someone give it a sanity check?
Please.

The problem here is JavaScript uses the + symbol for both joining strings and adding numbers.

Because your statement has a string in it (the "Next entry " part), it will assume it should treat everything as a string, so the 1 ends up being 11 - just as 8 would end up as 81.

The trick is to give the JavaScript interpreter a hint as to what order it should do the operations. I see you've used spaces in your statement, but you need to use brackets:

node.warn("Next entry " + (i+1) );

With those brackets, it will first do the i+1- where both sides are numbers, so it does numeric addition. It then does "Next entry " + <result of (i+1)> where there is a String, so it does a string join.

I hope that clarifies it.

1 Like

Yes, thanks Nic.

I was suspicious of doing that. It is I have just spent the last . . . . (long time) getting this working and am starting to lose self belief.

I'll go in and modify the code now.

That kind of lies with the old BASIC syntax. But . . . . . I am good at messing things up and just hadn't got around to trying that.

Self doubt isn't a good thing.

I've posted the working flow here if you want to look at it and have a look at what I did.

Working flow

Since we should all now be using newer versions of Node.js, we can also make use of ES6 features. So a nice way to output a string with an embedded simple calculation is:

node.warn( `Next entry ${i+1}` );

Note the backticks

1 Like

I think us JS muggles should stick with the simplest way of doing something :slight_smile:

You wizards can do things the fancy ways :slight_smile:
#KISS

1 Like

Haha, I would argue that, in this case, the fancy way may well be the easiest :grinning:

Anyway, it is through learning new ways that we keep ourselves youthful - or "childish" as our better halves would doubtless characterise things. :rofl: