是否可以将子流的引用更改为 Node-RED 上的不同子流?

Is it possible to change the referrence of a subflow to a different subflow on Node-RED?

我通常使用不同的 Node-RED 实例,我喜欢创建子流来封装代码。然而,我总是以这样的方式结束我的节点调色板:

我读过 this thread on the official 论坛,那里说在导入子流时复制子流的行为是 Node-RED 当时的工作方式。然而,这个帖子是从 2019 年 9 月开始的,这种行为仍然是真的吗?如果是,是否有解决此问题的“非官方”方法?我的猜测是进入一个文件,我在其中找到所有“exec node (2)”和“exec node (3)”并将其替换为“exec node”,这样当我重新启动 node-red 时,所有这些子流都将变为“exec节点”,我将能够擦除其他节点,因为它们不再在任何地方使用。可能吗?

手动解决

在查看 Node-RED 文件夹中的 flow_server.json 文件一段时间后,我找到了解决此问题的方法。基本上,您需要执行以下操作:

  1. 在您的 .node-red 文件夹中找到文件 flow_server.json(如果启用了项目功能,它就在文件夹项目中)
  2. 使用不同的名称之一备份此文件,以免在出现问题时不小心弄乱所有流程
  3. 获取两个节点的id:你想保留的那个和复制的那个
  4. 搜索并将所有 subflow:idSubflowToSubstitute 替换为 subflow:idSubflowToKeep。在我的例子中是:subflow:9e7f93e5.544bc8 到 subflow:caeb9890.9cdb18
  5. 重新启动 运行 Node-RED
  6. 的服务

PS:此解决方案假定复制的节点相同。我真的不知道使用不同的子流程执行此过程的后果。


子流解决方案

我还创建了一个子流程,它对我来说更简单。它依赖于为 Node-RED 激活 fs 库。在试验之前备份您的 flow_server.json 文件...

[{"id":"b8749b41.f740e","type":"subflow","name":"fix duplication (2)","info":"","category":"essencial","in":[{"x":520,"y":460,"wires":[{"id":"948937d8.1051a8"}]}],"out":[],"env":[{"name":"flowFile","type":"str","value":"/home/user/.node-red/flow_server.json"},{"name":"subflowToKeep","type":"str","value":""},{"name":"subflowToSubstitute","type":"str","value":""}],"color":"#A6D2FF","icon":"node-red/swap.svg"},{"id":"948937d8.1051a8","type":"function","z":"b8749b41.f740e","name":"fix duplication","func":"const fs = global.get('fs');\n\nconst flowFile = env.get(\"flowFile\");\nconst subflowToKeep = env.get(\"subflowToKeep\")\nconst subflowToSubstitute = env.get(\"subflowToSubstitute\");\n\nlet flowString;\nlet flowObject;\n\ntry {\n    flowString = fs.readFileSync(flowFile, 'utf8');\n    flowObject = JSON.parse(flowString);\n\n    if (checkIfSubflowExists(subflowToKeep) && checkIfSubflowExists(subflowToSubstitute)) {\n        let subflowToKeepString = \"\";\n        let subflowToSubstituteString = \"\";\n        flowObject.forEach(({ type, name, id }) => {\n            if ( type === 'subflow'){\n                switch(name) {\n                    case subflowToKeep:\n                        subflowToKeepString = `subflow:${id}`\n                        node.warn(name + \"- \" + subflowToKeepString);\n                        break;\n                    case subflowToSubstitute:\n                        subflowToSubstituteString = `subflow:${id}`\n                        node.warn(name + \"- \" + subflowToSubstituteString);\n                        break;\n                }\n            }\n        });\n\n        if ( subflowToSubstituteString !== \"\" && subflowToKeepString !== \"\" ){\n            var regex = new RegExp(subflowToSubstituteString, \"g\");\n                if ( flowString.search(regex) >= 0 ){\n                    flowString = flowString.replace(regex, subflowToKeepString);\n                    fs.writeFileSync(flowFile, flowString );\n                    node.warn(\"nodes updated! restart node-red.\")\n                    return msg;\n                }\n        }\n    }\n    node.warn(\"Nothing to do. Check the input parameters correctly...\");\n    return msg;\n} catch(err){\n    node.warn(err)\n    return msg;\n}\n\n// auxiliary functions\nfunction checkIfSubflowExists(key){\n    let hasKey = false;\n    flowObject.forEach(({ type, name }) => {\n        if ( type === 'subflow'){\n            if ( name === key ){\n                hasKey = true;\n            }\n        }\n    });\n    return hasKey;\n}\n","outputs":0,"noerr":0,"x":860,"y":460,"wires":[]},{"id":"a437e02b.0f67d8","type":"subflow:b8749b41.f740e","z":"26278f81.44628","name":"","env":[],"x":1190,"y":380,"wires":[]}]