TL;DR InfluxDB技术提示:处理JSON对象和数组映射
作者:Anais Dotis-Georgiou / 产品,用例,开发者
2022年5月11日
导航到
有多种方法可以使用Flux从各种不同的来源导入数据,包括SQL数据库、其他InfluxDB Cloud账户、来自URL的标注CSV和JSON。然而,之前您只能像这个示例中描述的那样手动使用Flux从JSON对象构建表。
我们将描述如何使用三个具有越来越复杂JSON类型的示例。首先,我们将使用元语言示例描述如何使用这些JSON类型。然后,我们将通过使用OpenWeatherMap API的实例来讨论现实生活中的例子。
在使用Flux处理JSON对象时,以下函数和注意事项非常重要
- display()函数:使用此函数将任何值的Flux表示形式作为字符串返回。这允许您在InfluxDB UI中可视化您的JSON对象。此功能在最新的开源版本中也已发布,请确保您的软件是最新的。
- array.from()函数:使用此函数与display()函数一起在InfluxDB UI中以字符串形式查看JSON对象。我们将在以下部分讨论如何一起使用这两个函数。
- json.parse() 函数:使用此函数将 JSON 对象转换为 Flux 值。有关类型转换,请参阅这里。在使用 http.post() 进行 API 调用时,您必须将此函数应用于 JSON 对象响应。
- time() 函数:使用此函数将字符串时间戳转换为时间值。
- array.map() 函数:使用此函数遍历数组以处理复杂的 JSON 类型。
JSON 示例 1
第一个示例:从键中提取顶层值。
- 将以下 JSON 转换为
JSON = {"a": 1, "b": 2, "c": 3, "time": timestamp_1}
- 以下 Flux 表格
time a b c timestamp_1 1 2 3 - 以下 Flux 代码
jsonData = json.parse(data: JSON) // uncomment the next line to display the JSON // array.from(rows: [{data: display(v: jsonData)}]) // convert the timestamp to a time type with the time() function // use the array.from() function to create a table array.from(rows: [{_time: time(v: int(v: jsonData.timestamp_1)) , a: jsonData.a, b: jsonData.b, c: jsonData.c }])
- 在此处找到运行此示例的代码 这里。
JSON 示例 2
第二个示例:在具有复杂类型的数组上映射。
- 将以下 JSON 转换为
JSON = {"a": 1, "list": [{"b": 1.1, "time": timestamp_1}, {"b": 1.2, "time": timestamp_2} ] }
- 以下 Flux 表格
time a b timestamp_1 1 1.1 timestamp_2 1 1.2 - 以下 Flux 代码
jsonData = json.parse(data: JSON) // uncomment the next line to display the JSON // array.from(rows: [{data: display(v: jsonData)}]) // extract the list that we want to map across with array.map listData = jsonData.list // gather any top level values that you want to include in your table as constants a = jsonData.a // map across each complex type in the array named "list" list = array.map( arr: listData, fn: (x) => ({ // convert the timestamp to a time type with the time() function "_time": time(v::x.time), "b": x.b, "city": a }) ) // finally convert that flattened list into a table with array.from array.from(rows: list)
- 在此处找到运行此示例的代码 这里。
JSON 示例 3
第三个示例:在包含复杂类型的嵌套数组上映射。
- 将以下 JSON 转换为
JSON = {"list": [{"b": 1.1, "nestedList": [{"alpha": "foo1", "beta": "bar1"}, {"alpha": "foo2", "beta": "foo2"}], "time": 1596632400000000000}, {"b": 1.2, "nestedList": [{"alpha": "foo1", "beta": "bar1"}, {"alpha": "foo2", "beta": "foo2"}], "time": 1596632500000000000} ] }
- 以下 Flux 表格
time alpha b timestamp_1 foo1 1.1 timestamp_2 foo1 1.2 - 以下 Flux 代码
jsonData = json.parse(data: JSON) // uncomment the next line to display the JSON // array.from(rows: [{data: display(v: jsonData)}]) // extract the list that we want to map across with array.map listData = jsonData.list // map across each complex type in the array named "list" list = listData |> array.map(fn:(x) => { pendingList = x.nestedList return { id: x.b, _time: time(v: int(v: x.time)), alpha: pendingList[0].alpha, } }) array.from(rows: list)
- 在此处找到运行此示例的代码 这里。
JSON 示例 4
第四个示例:在包含嵌套数组的复杂类型上映射,并评估值是否存在。此示例与示例 3 类似,但它可以用于处理可能包含 null 值的实例。
- 将以下 JSON 转换为
JSON = {"list": [{"b": 1.1, "nestedList": [{"alpha": "foo1", "beta": "bar1"}, {"alpha": "foo2", "beta": "foo2"}], "time": 1596632400000000000}, {"b": 1.2, "nestedList": [{"alpha": "null", "beta": "bar1"}, {"alpha": "foo2", "beta": "foo2"}], "time": 1596632500000000000} ] }
- 以下 Flux 表格
time alpha b timestamp_1 foo1 1.1 timestamp_2 foo1 1.2 - 以下 Flux 代码
jsonData = json.parse(data: JSON) // uncomment the next line to display the JSON // array.from(rows: [{data: display(v: jsonData)}]) // extract the list that we want to map across with array.map listData = jsonData.list // map across each complex type in the array named "list" list = listData |> array.map(fn:(x) => { pendingList = x.nestedList // filter for the value |> array.filter(fn: (x) => x.alpha == "foo1") // handle null values pendingAlpha = if length(arr: pendingList) == 1 then pendingList[0].alpha else "foo1" return { id: x.b, _time: time(v: int(v: x.time)), alpha: pendingAlpha, } }) array.from(rows: list)
- 在此处找到运行此示例的代码 这里。
OpenWeatherMap API 示例:复杂类型的数组
在此示例中,我们将了解如何映射包含嵌套 JSON 对象的数组以构建表格,这使得在 Flux 中处理 JSON 更加容易。最后,我们将使用 Flux 将表格写入 InfluxDB,步骤如下
- 使用 http.get() 函数提交 GET 请求到 API 并返回 JSON 对象。
- 使用 json.encode() 函数将对象转换为字节。
- 使用 json.parse() 函数将 JSON 对象或数组转换为 Flux 记录或数组。
- 使用 array.map() 函数映射数组中的元素。
- 使用 array.from() 函数构建表格。
- 使用 to() 函数将数据写入 InfluxDB。
在本节中,我们将使用 OpenWeatherMap 当前天气数据 API 使用 小时预测端点 收集过去 4 天内伦敦的每小时天气数据。我们返回的 JSON 响应有 96 个时间戳,如下所示
{
"cod": "200",
"message": 0.0179,
"cnt": 96,
"list": [
{
"dt": 1596632400,
"main": {
"temp": 289.16,
"feels_like": 288.41,
"temp_min": 289.16,
"temp_max": 289.16,
"pressure": 1013,
"sea_level": 1013,
"grnd_level": 1010,
"humidity": 78,
"temp_kf": 0
},
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04n"
}
],
"clouds": {
"all": 100
},
"wind": {
"speed": 2.03,
"deg": 252,
"gust":5.46
},
"visibility": 10000,
"pop": 0.04,
"sys": {
"pod": "n"
},
"dt_txt": "2020-08-05 13:00:00"
},
.....
],
"city": {
"id": 2643743,
"name": "London",
"coord": {
"lat": 51.5085,
"lon": -0.1258
},
"country": "GB",
"timezone": 0,
"sunrise": 1568958164,
"sunset": 1569002733
}
}
以下 Flux 代码
- 导入必要的库
- 将请求对象存储在变量 resp 中
- 解析响应的 JSON 主体并将列表属性存储在变量 nestedListData 中。此属性包含包含伦敦时间戳和温度的数组列表。
- 映射对象列表以提取日期和时间。温度作为主属性中的嵌套数组存在。Unix 日期时间值通过乘以 1000000000 转换为纳秒精度。使用 time() 函数将 Unix 时间戳转换为 RFC3339 格式。此时间戳转换执行是为了更好地可视化数据。
- 使用array.from()函数构建表格,并将提取的时间、温度值列表传入。
- 使用set()函数创建名为_weather和_field的列,分别对应值为"weather"和"temp"。这是为使用需要您的表具有以下列的to()函数做准备:
- _time
- _measurement
- _field
- _value
- 使用to()函数将数据写入名为"bucket"的桶。
import "experimental/json"
import "experimental/http"
import "experimental/array"
weatherURL = "https://pro.openweathermap.org/data/2.5/forecast/hourly?lat=35&lon=139&appid=<yourAPIkey>
// http.get() returns the response from the API
resp = http.get(url: weatherURL)
// json.parse function returns a json object with lists, records, strings, booleans, and floats
jsonData = json.parse(data: resp.body)
// get the list object
listData = jsonData.list
// extract the city name just once
city = jsonData.city.name
list = array.map(
arr: listData,
fn: (x) => ({
// convert the timestamp to a time type with the time() function
"_time": time(v::x.dt*1000000000),
"_value": x.main.temp,
"city": city
})
)
array.from(rows: list)
|> set(key: "_field", value: "temp")
|> set(key: "_measurement", value: "weather")
|> yield()
|> to(bucket: "bucket")
关于使用Flux处理JSON对象的最终想法
希望这篇InfluxDB技术技巧帖子能激发您利用Flux来请求和操作JSON响应。现在您可以使用array.map()函数映射JSON中的嵌套数组来构建行。像往常一样,您可以使用array.from()函数从这些行中构建表格。在准备输出以符合to()函数的数据要求后,我们最终能够写入表格。这种功能为将数据导入InfluxDB提供了另一种方式。您可以在任务中按计划执行此逻辑,定期从HTTP请求中写入数据。
如果您使用Flux并需要帮助,请在我们的社区网站或Slack频道中寻求帮助。如果您正在InfluxDB之上开发酷炫的IoT应用,我们非常乐意了解,请确保分享您的故事!另外,请分享您的想法、担忧或问题在评论部分。我们非常乐意收到您的反馈并帮助您解决遇到的问题!