使用地图或模板在节点流中转换 JSON

Posted

技术标签:

【中文标题】使用地图或模板在节点流中转换 JSON【英文标题】:Transforming JSON in a node stream with a map or template 【发布时间】:2015-07-26 07:41:16 【问题描述】:

我对 javascript 和 Node 比较陌生,我喜欢边做边学,但是我对 Javascript 设计模式缺乏认识,这让我对尝试重新发明***持谨慎态度,我想从社区中知道如果什么我想做的已经以某种形式存在,我不是在寻找下面示例的特定代码,只是朝着正确的方向轻推以及我应该搜索的内容。

我基本上想创建自己的私有 IFTTT/Zapier,用于将数据从一个 API 插入另一个 API。

我使用节点模块 requestGET 数据从一个 API,然后 POST 到另一个。

request 支持流式处理来做这样的整洁的事情:

request.get('http://example.com/api')
  .pipe(request.put('http://example.com/api2'));

在这两个请求之间,我想通过转换管道 JSON,挑选我需要的键/值对并将键更改为目标 API 所期望的。

request.get('http://example.com/api')
  .pipe(apiToApi2Map)
  .pipe(request.put('http://example.com/api2'));

这是来自源 API 的 JSON 示例:http://pastebin.com/iKYTJCYk

这就是我想转发的内容:http://pastebin.com/133RhSJT

在这种情况下,转换后的 JSON 从每个对象“属性”键的值和每个对象“值”键的值中获取键。

所以我的问题:

是否有框架、库或模块可以简化转换步骤?

流媒体是我应该处理的方式吗?这似乎是一种优雅的方法,因为我已经使用request 创建了一些 Javascript 包装函数来轻松访问 API 方法,我只需要弄清楚中间步骤。

是否可以为这些转换创建“模板”或“地图”?假设我想更改源 API 或目标 API,最好创建一个将源映射到所需目标键/值的新文件。

希望社区可以提供帮助,我愿意接受任何和所有建议! :) 这是我正在进行的一个开源项目,所以如果有人想参与,请与我们联系。

【问题讨论】:

【参考方案1】:

正如 Andrew 指出的那样,有直通或事件流,但是我做了一些更容易使用的东西,scramjet。它的工作方式与 through 相同,但它的 API 几乎与 Arrays 相同,因此您可以轻松使用 map 和 filter 方法。

您的示例代码是:

DataStream
   .pipeline(
       request.get('http://example.com/api'),
       JSONStream.parse('attributes.items.*')
   )
   .filter((item) => item.attibute)  // filter out ones without attribute
   .reduce((acc, item) => 
       acc[item.attribute] = item.value;
       return acc;
   .then((result) => request.put('http://example.com/api2', result))
;

我想这更容易使用 - 但是在这个例子中,你确实将数据累积到一个对象中 - 所以如果 JSON 实际上比这长得多,你可能想再次将它转回 JSONStream。

【讨论】:

【参考方案2】:

是的,您绝对是在正确的轨道上。我会向您指出两个流库,through 可以更轻松地定义您自己的流,JSONStream 有助于将二进制流(就像您从 request.get 得到的)转换为已解析的流JSON 文档。下面是一个使用这两种方法来帮助您入门的示例:

var through = require('through');
var request = require('request');
var JSONStream = require('JSONStream');
var _ = require('underscore');

// Our function(doc) here will get called to handle each
// incoming document int he attributes array of the JSON stream
var transformer = through(function(doc) 
    var steps = _.findWhere(doc.items, 
        label: "Steps"
    );
    var activeMinutes = _.findWhere(doc.items, 
        label: "Active minutes"
    );
    var stepsGoal = _.findWhere(doc.items, 
        label: "Steps goal"
    );

    // Push the transformed document into the outgoing stream
    this.queue(
        steps: steps.value,
        activeMinutes: activeMinutes.value,
        stepsGoal: stepsGoal.value
    );
);

request
    .get('http://example.com/api')
    // The attributes.* here will split the JSON stream into chunks
    // where each chunk is an element of the array
    .pipe(JSONStream.parse('attributes.*'))
    .pipe(transformer)
    .pipe(request.put('http://example.com/api2'));

【讨论】:

哇,谢谢@Andrew,非常直截了当。我可以从下划线文档中看到_.findWhere 的第一个参数是数据,但我不明白item.items。为什么需要.items 它来自您的 pastebin 示例。每个attributes 都有一个items 数组。 我是傻瓜!我现在和你在一起。 :)

以上是关于使用地图或模板在节点流中转换 JSON的主要内容,如果未能解决你的问题,请参考以下文章

如何在freemarker中输出json文档的整个节点

将单个xml节点作为数组转换为json

将 JSON 转换为地图

转换地图 到JSON并返回Map

如何在 HugSQL 结果中将返回的地图转换为 json csv

将首先转换为 Observable 的 json 文件转换为打字稿中的地图,角度