将数据存储在 Node-Red 变量中
节点红色节点在节点之间传递msg 对象。
然而,这个对象被下一个msg 对象替换。那么如何在节点调用之间存储数据呢?
Node-Red 提供了三种机制:
- 所述上下文对象-stores数据的节点
- 该流对象-针对流存储数据
- 在全局对象-stores数据画布
我将使用如下所示的简单流程来说明这些方法。
注入节点用于启动流程,然后函数节点实现计数器,调试节点显示结果。
这个想法是计算消息被注入的次数。
注入的实际消息并不重要。
注意:本教程附带一个视频,因为使用视频可以轻松演示变量之间的交互。您可能希望快速通读文本,然后转到视频。这是视频
使用上下文对象
这用于存储函数变量。
取值和存储的过程是使用对象的get方法取值和set方法存储值:
name =context.get("name"); //检索变量
context.set("name",name); // 存储变量
在上下文对象中为函数 1 存储的变量对函数 2 不可用,反之亦然。
初始化变量
标准方法是在脚本顶部包含此代码:
var count=context.get('count') || 0;
这意味着 - 如果上下文对象中不存在计数,则使我们的局部变量计数为零;否则将存储的值分配给我们的局部变量计数。
您可以使用多个变量,例如
var count=context.get('count') || 0;
var count2=context.get('count2') || 0;
您还可以使用数组或对象,例如
var local=context.get('data') || {};
if (local.count===undefined) //测试存在
{
local.count=0;
}
在上面的代码中,data 是存储在上下文对象中的对象,local 是我们的本地对象。
下面是一个示例脚本,它使用单个变量作为函数 1 中的计数器:
var count=context.get('count') || 0;
计数 +=1;
msg.payload="F1 "+msg.payload+" "+count;
context.set('count',count);
回消息;
请注意,上述语法在 Internet 上很常见,但由于 JavaScript 识别 True 和 False 的方式,它确实会导致奇怪的问题。
那里代替
var count=context.get('count') || 0;
我更喜欢使用这种格式:
var count=context.get('count') ;
如果(类型计数==“未定义”)
计数=0;
这是一个示例脚本,它使用对象变量作为函数 2 中的计数器:
var local=context.get('data') || {};
if (local.count ===undefined)//测试存在
{
local.count=0;
}
local.count +=1;
msg.payload="F2 "+msg.payload+" "+local.count;
context.set('data',local);
回消息;
如果您查看函数 1 和函数 2 的代码,您将看到它们使用相同的计数器变量。
但是,当您单击功能 1 的注入节点时,您会看到计数器值为 1,然后功能 2 的注入节点也是 1。
这表明计数器对于每个函数都是本地的,而不是在函数之间共享。
注意:目前,如果您重新启动流程,变量将被重置,但这可能会发生变化。
使用流对象
您可以以与上下文对象相同的方式使用流对象。
要检索存储在流对象中的值,请使用:
var count=flow.get('count') || 0;
并存储值使用:
flow.set('count',count);
这次您应该注意到函数可以共享存储在流对象中的变量。看视频
使用全局对象
您可以以与上下文对象相同的方式使用流对象。
要检索存储在流对象中的值,请使用:
var count=global.get('count') || 0;
并存储值使用:
global.set('count',count);
这一次您应该注意到,这些函数甚至可以跨流共享存储在全局对象中的变量。
视频 - 如何在节点红色变量中存储数据
视频中使用的流程
存储和检索多个变量
在 node-red 0.19 版本中,可以一次存储和检索多个变量。所以不要使用:
var v1=flow.get("v1");
var v2=flow.get("v2");
//您可以使用
var values=flow.get(["v1","v2"]);
var v1=values[0];
var v2=values[1];
//和
flow.set("v1",v1);
flow.set("v2",v2);
//您可以使用
flow.set(["v1","v2"],[1,2]);
如果您查看商店中的变量,您会发现它们被存储为单独的变量,如下面的屏幕截图所示。屏幕截图还显示了如何存储变量数组(数据):
在文件系统中存储上下文数据
存储在 context、flow 和 glbal 变量中的数据称为上下文数据,通常存储在内存中。
这意味着如果您重新启动流程,则数据将丢失。
然而,从 0.19 版本开始,可以将上下文数据存储在文件系统中。
为此,您需要修改设置文件并添加以下条目:
上下文存储:{
默认值:“仅内存”,
仅内存:{ 模块:'内存'},
文件:{ 模块:'本地文件系统'}
},
您将它放在设置文件中的哪个位置并不重要,并且根据您开始使用的 node-red 版本,您可能已经有一个被注释掉的条目。
上面的设置将 node-red 配置为使用内存中的默认存储以及文件存储的文件系统。
因此,我们有两家商店。
将数据保存到上下文变量或从中检索数据时,您需要指定它们所在的存储。默认值在内存中。
所以如果你使用:
var count=context.get("count");
您将从内存中检索计数变量并从文件存储中获取计数变量使用:
context.get("count", "file");
存储数据使用:
context.set("count", count,"file");
系统将变量存储在.node-red文件夹下名为context的文件夹中的 JSON 文件中。
即使您将数据存储在文件系统中,仍然可能丢失数据,因为数据仅每 30 秒刷新一次到文件系统。
您可以更改此设置(并非真正需要),其他配置选项请参阅此处的文档。
您还应该注意,您可以有两个名称相同但存储在内存和文件系统中的变量,如下面的屏幕截图所示:
无需电线即可在节点之间交换数据
节点红色消息通常使用连线在节点之间传递。
然而,可以在节点之间传递数据,并使用流和全局对象将它们连接在一起。
附带源码1:
[{
"id": "e5d17b06.1eb23",
"type": "function",
"z": "9b79d705.36516",
"name": "Function 1",
"func": "var count=context.get('count') || 0;\ncount +=1;\nmsg.payload=\"F1 \"+msg.payload+\" \"+count;\ncontext.set('count',count);\nreturn msg;\n//\n//",
"outputs": 1,
"noerr": 0,
"x": 259,
"y": 34,
"wires": [
["8a701147.e5911"]
]
}, {
"id": "8a701147.e5911",
"type": "debug",
"z": "9b79d705.36516",
"name": "",
"active": true,
"console": "false",
"complete": "false",
"x": 409,
"y": 94,
"wires": []
}, {
"id": "27f735da.096c92",
"type": "inject",
"z": "9b79d705.36516",
"name": "",
"topic": "sensors/sensor1",
"payload": "ON",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 119,
"y": 103,
"wires": [
["e5d17b06.1eb23"]
]
}, {
"id": "888c9d4f.3d53b",
"type": "inject",
"z": "9b79d705.36516",
"name": "",
"topic": "sensors/sensor1",
"payload": "ON",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 117,
"y": 423,
"wires": [
["acd1780e.a5dfa"]
]
}, {
"id": "acd1780e.a5dfa",
"type": "function",
"z": "9b79d705.36516",
"name": "Uses Object",
"func": "var local=context.get('data') || {};\nif (local.count===undefined)//test exists\n{\n local.count=0;\n}\nlocal.count +=1;\nmsg.payload=\"F2 \"+msg.payload+\" \"+local.count;\ncontext.set('data',local);\nreturn msg;\n//",
"outputs": 1,
"noerr": 0,
"x": 280,
"y": 380,
"wires": [
["cfb44101.06c7b8"]
]
}, {
"id": "cfb44101.06c7b8",
"type": "debug",
"z": "9b79d705.36516",
"name": "",
"active": true,
"console": "false",
"complete": "false",
"x": 449,
"y": 412,
"wires": []
}, {
"id": "7ca45479.2ff8e4",
"type": "inject",
"z": "9b79d705.36516",
"name": "",
"topic": "sensors/sensor1",
"payload": "ON",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 122,
"y": 595,
"wires": [
["7481cdd9.be607c"]
]
}, {
"id": "7481cdd9.be607c",
"type": "function",
"z": "9b79d705.36516",
"name": "With Flow",
"func": "//var count=context.get('count') || 0;\nvar count=flow.get('count') || 0;\n\ncount +=1;\nmsg.payload=\"F5 \"+msg.payload+\" \"+count;\nflow.set('count',count);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 274,
"y": 507,
"wires": [
["b3c59ea2.ba4068"]
]
}, {
"id": "b3c59ea2.ba4068",
"type": "debug",
"z": "9b79d705.36516",
"name": "",
"active": true,
"console": "false",
"complete": "false",
"x": 396,
"y": 601,
"wires": []
}, {
"id": "c70a28a9.3f0018",
"type": "inject",
"z": "9b79d705.36516",
"name": "",
"topic": "sensors/sensor1",
"payload": "ON",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 126,
"y": 696,
"wires": [
["e8f1d04c.d13e7"]
]
}, {
"id": "e8f1d04c.d13e7",
"type": "function",
"z": "9b79d705.36516",
"name": "With Flow",
"func": "var count=flow.get('count') || 0;\n\ncount +=2;\nmsg.payload=\"F6 \"+msg.payload+\" \"+count;\nflow.set('count',count);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 271,
"y": 647,
"wires": [
["b7894834.f9cd18"]
]
}, {
"id": "b7894834.f9cd18",
"type": "debug",
"z": "9b79d705.36516",
"name": "",
"active": true,
"console": "false",
"complete": "false",
"x": 405,
"y": 698,
"wires": []
}, {
"id": "3f5132b9.9a3e9e",
"type": "inject",
"z": "9b79d705.36516",
"name": "",
"topic": "sensors/sensor1",
"payload": "ON",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 95,
"y": 331,
"wires": [
["3088f4d0.0b0ee4"]
]
}, {
"id": "3088f4d0.0b0ee4",
"type": "function",
"z": "9b79d705.36516",
"name": "Multiple variables",
"func": "var count=context.get('count') || 0;\nvar count2=context.get('count2') || 0;\n\n//\n\ncount +=1;\ncount2 +=2;\nmsg.payload=\"F3 \"+msg.payload+\" \"+count +\" \"+count2;\ncontext.set('count',count);\ncontext.set('count2',count2);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 279,
"y": 290,
"wires": [
["d697d513.62e288"]
]
}, {
"id": "d697d513.62e288",
"type": "debug",
"z": "9b79d705.36516",
"name": "",
"active": true,
"console": "false",
"complete": "false",
"x": 452,
"y": 340,
"wires": []
}, {
"id": "6e75a3b.86afe5c",
"type": "inject",
"z": "9b79d705.36516",
"name": "",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"x": 89,
"y": 782,
"wires": [
["cafe0896.b37a9"]
]
}, {
"id": "cafe0896.b37a9",
"type": "function",
"z": "9b79d705.36516",
"name": "Reset",
"func": "var count=flow.get('count') || 0;\n\ncount =0;\nflow.set('count',count);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 266,
"y": 781,
"wires": [
[]
]
}, {
"id": "56e788bf.bbda5",
"type": "inject",
"z": "9b79d705.36516",
"name": "",
"topic": "sensors/sensor1",
"payload": "ON",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 147,
"y": 933,
"wires": [
["5457ea02.df34b4"]
]
}, {
"id": "5457ea02.df34b4",
"type": "function",
"z": "9b79d705.36516",
"name": "With Global",
"func": "\nvar count=flow.get('count') || 0;\nvar gcount=global.get('count') || 0;\n\ncount +=1;\nmsg.payload=\"F10 \"+\" flow= \"+count+ \" global= \"+gcount;\nflow.set('count',count);\nglobal.set('count',gcount);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 296,
"y": 840,
"wires": [
["1cbca862.39b138"]
]
}, {
"id": "1cbca862.39b138",
"type": "debug",
"z": "9b79d705.36516",
"name": "",
"active": true,
"console": "false",
"complete": "false",
"x": 459,
"y": 921,
"wires": []
}, {
"id": "da4f24ed.b574f8",
"type": "inject",
"z": "9b79d705.36516",
"name": "",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"x": 138,
"y": 1046,
"wires": [
["544190ee.2cdd08"]
]
}, {
"id": "544190ee.2cdd08",
"type": "function",
"z": "9b79d705.36516",
"name": "Global Reset",
"func": "var count=flow.get('count') || 0;\n\ncount =0;\nflow.set('count',count);\nglobal.set('count',count);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 335,
"y": 1045,
"wires": [
[]
]
}, {
"id": "42a05a43.6656c4",
"type": "inject",
"z": "9b79d705.36516",
"name": "",
"topic": "sensors/sensor1",
"payload": "ON",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 126,
"y": 211,
"wires": [
["29635145.d19c66"]
]
}, {
"id": "29635145.d19c66",
"type": "function",
"z": "9b79d705.36516",
"name": "Function 2",
"func": "var count=context.get('count') || 0;\nnode.log(count);\n//\n\ncount +=1;\nmsg.payload=\"F1 \"+msg.payload+\" \"+count;\ncontext.set('count',count);\nreturn msg;\n//\n//",
"outputs": 1,
"noerr": 0,
"x": 283,
"y": 152,
"wires": [
["4d077fc.63245"]
]
}, {
"id": "4d077fc.63245",
"type": "debug",
"z": "9b79d705.36516",
"name": "",
"active": true,
"console": "false",
"complete": "false",
"x": 455,
"y": 201,
"wires": []
}]
附带源码2:
[{
"id": "c8fd27c.5903358",
"type": "inject",
"z": "3d8b3bc.2f4e344",
"name": "",
"topic": "sensors/sensor1",
"payload": "ON",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 117,
"y": 172,
"wires": [
["6c6c002d.2fc9d"]
]
}, {
"id": "6c6c002d.2fc9d",
"type": "function",
"z": "3d8b3bc.2f4e344",
"name": "With Global",
"func": "\nvar count=flow.get('count') || 0;\nvar gcount=global.get('count') || 0;\n\ncount +=1;\ngcount +=5;\nmsg.payload=\"F10 \"+\" flow= \"+count+ \" global= \"+gcount;\nflow.set('count',count);\nglobal.set('count',gcount);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 244,
"y": 79,
"wires": [
["9df3d6c7.acb6"]
]
}, {
"id": "9df3d6c7.acb6",
"type": "debug",
"z": "3d8b3bc.2f4e344",
"name": "",
"active": true,
"console": "false",
"complete": "false",
"x": 407,
"y": 160,
"wires": []
}]