使用地图或模板在节点流中转换 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。
我使用节点模块 request
到 GET
数据从一个 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的主要内容,如果未能解决你的问题,请参考以下文章