如何在Node Red中创建灵活的JSON结构?

时间:2019-01-30 15:36:59

标签: json csv object node-red

假设我有以下CSV文件:

A_Key;B_Key;C_Key;...;X_Key
Value 1;2;Value 1.3;...;Value 1.24
Value 1;;Value 2.3;...;Value 2.24
...

我已经创建了一个节点红色模板,该模板允许我提取一些键值对以创建简单的JSON输出。但是,这是一对一的关系,但是我需要一个更灵活的解决方案。对于应该产生输出的对象有一些要求:

  1. 所有行都有一列用作主键-假设这是“ C键”列。此主键必须位于结果对象中。在我们的示例中,第二列“ A Key”包含对象的类型。它是常量,因此被忽略。
  2. 在其余的列中,有一个必须上载的特定列表,但是某些字段可能为空(在这种情况下,NULL应该是值)。这些字段在名为“属性”的子对象中列出
  3. 在CSV中可能缺少完整的列。如果这是必填列,则所有对象都应仍具有键,尽管键的值为NULL。
  4. CSV可能会包含其他不在必填列表中的列。这些可选属性应出现在名为“ Extras”的“包罗万象”子对象中。

上面的CSV生成的对象看起来像这样:

[
    {
        "A_Key": "Value 1",
        "C_Key": "Value 1.3",
        "Properties": {
            "B_Key": "2",
            "F_Key": ...,
            ...
            "X_Key": "Value 1.24"
        },
        "Extras": {
           "D_Key": ...,
           "E_Key": ...,
           ...
        }
    },
    {
        "A_Key": "Value 1",
        "C_Key": "Value 2.3",
        "Properties": {
            "B_Key": "NULL",
            "F_Key": ...,
            ...
            "X_Key": "Value 2.24"
        },
        "Extras": {
           "D_Key": ...,
           ...
        }
    },
]

我想执行以下操作:我想在Node Red中构建一个功能节点“ Prepare JSON”,该节点遍历CSV的列并将列标题用作生成的JSON的键。我已经在流程的开头准备了一个设置所需变量的函数:

var primaryKey = "C_Key";
var mandatoryPart = "Properties";
var mandatoryKeys = ["B_Key",
"F_Key",
...
"X_Key"];
var optionalPart = "Extras";
var appendOptionalPart = true;

msg.primaryKey = primaryKey;
msg.mandatoryPart = mandatoryPart
msg.mandatoryKeys = mandatoryKeys;
msg.optionalPart = optionalPart;
msg.appendOptionalPart = appendOptionalPart;

我尝试了几种方法来运行“准备JSON”功能:

msg.payload = {
    "A_Key": "Value 1",
    "C_Key": msg.payload.C_Key,
    "Properties": {
        "B_Key": msg.payload.B_Key
    },
    optionalPart: msg.optionalPart
}

//for(var i =0; i<msg.mandatoryParts.length;i++)
//{  
//  msg.payload.Properties.push(msg.payload[msg.mandatoryKeys[i]].value);
//    msg.payload.Properties.push(msg.mandatoryKeys[i]);
//}
return msg;

顶部的静态部分工作正常,但是,如何动态设置元素键的名称呢?看一下“ optionalPart”行:变量是“ msg.optionalPart”,但是当我尝试直接访问它时,Node Red抱怨该点。我尝试将其用转义引号引起来,但Node Red也不喜欢该行开头的反斜杠字符。我还尝试了字符串连接,当然,如果我将变量名放在引号中,则将其原样打印在输出中...

底部的注释部分是我第一次尝试遍历元素,我也被困在这里。非常感谢您的帮助!

这是当前流程的图像:

Current configuration of the flow

1 个答案:

答案 0 :(得分:0)

这可以通过JSONata轻松完成,JSONata是一种简化数据转换的语言。

Node-RED流的主要部分将是具有以下JSONata表达式的变更节点:

payload.{"A_Key" :A_Key, "C_Key" :C_Key, "Properties" : {"B_Key" :B_Key, "F_Key" :F_Key, "X_Key" :X_Key}, "Extras" : {"D_Key" :D_Key, "E_Key" :E_Key }}

这是要为您的Node-RED导入的流程,只需修复文件名路径:

[{"id":"52781b93.a86794","type":"tab","label":"Flow 3","disabled":false,"info":""},{"id":"fc475896.7f6a68","type":"csv","z":"52781b93.a86794","name":"","sep":",","hdrin":true,"hdrout":"","multi":"mult","ret":"\\n","temp":"","skip":"0","x":430,"y":260,"wires":[["c6f562e7.6189c"]]},{"id":"282d5fcd.692cb","type":"debug","z":"52781b93.a86794","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":770,"y":260,"wires":[]},{"id":"22fa22d.c2868de","type":"inject","z":"52781b93.a86794","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":260,"wires":[["93544cf8.57fad"]]},{"id":"93544cf8.57fad","type":"file in","z":"52781b93.a86794","name":"Read CSV","filename":"f1.csv","format":"utf8","chunk":false,"sendError":false,"x":280,"y":260,"wires":[["fc475896.7f6a68"]]},{"id":"c6f562e7.6189c","type":"change","z":"52781b93.a86794","name":"Prepare JSON","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.{\"A_Key\" :A_Key, \"C_Key\" :C_Key, \"Properties\" : {\"B_Key\" :B_Key, \"F_Key\" :F_Key, \"X_Key\" :X_Key}, \"Extras\" : {\"D_Key\" :D_Key, \"E_Key\" :E_Key }}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":600,"y":260,"wires":[["282d5fcd.692cb"]]}]

编辑:为您有关动态元素键的问题添加一个可能的答案。

如果我正确理解,您想向msg.payload添加可变的密钥。为此,您可以使用Javascript Computed Property Names

在您的功能节点中,将是这样的:

msg.payload = {
    "A_Key": "Value 1",
    "C_Key": msg.payload.C_Key,
    "Properties": {
        "B_Key": msg.payload.B_Key
    },
    //optionalPart: msg.optionalPart
    [optionalPart]:["Z_Key"]
    // or [msg.optionalPart]:["Z_Key"] if more appropriate for your logic
}

您将在msg.payload中添加属性键“ Extras”。

作为旁注(由于这不是您的OP的一部分),请注意,如果msg.payload.C_Keymsg.payload.B_Key的初始化不正确,代码下面的内容尚不清楚,并且可能会引起麻烦。

"C_Key": msg.payload.C_Key,
"B_Key": msg.payload.B_Key,