如何使用 jq select 来自 JSON 字符串的日期范围?
How to select a date range from a JSON string by using jq?
我有一个像这样的 JSON 字符串 (MacOS):
[{
"id": 3624,
"created_at": "2016-10-21T20:51:16.000+08:00",
},
{
"id": 3625,
"created_at": "2016-10-22T08:09:16.000+08:00",
},
{
"id": 3626,
"created_at": "2016-10-23T09:19:55.000+08:00",
}]
我想 select "created_at" 从“2016-10-21”到“2016-10-22”;
我想得到这样的结果:
[{
"id": 3624,
"created_at": "2016-10-21T20:51:16.000+08:00",
},
{
"id": 3625,
"created_at": "2016-10-22T08:09:16.000+08:00",
}]
有人能给我指出正确的方向吗?
问题已解决
现在,我使用此代码 select 精确到分钟,我希望它对其他人有用:
jq --arg s '2016-10-26T18:16' --arg e '2016-10-27T20:24' '[($s, $e) | strptime("%Y-%m-%dT%H:%M") | mktime] as $r
| map(select(
(.updated_at[:19] | strptime("%Y-%m-%dT%H:%M:%S") | mktime) as $d
| $d >= $r[0] and $d <= $r[1]))' <<< "$requestJson"
根据要求使用命令行 JSON 解析器 jq
:
注意: 演示了很多很棒的高级 jq
技术,但对于手头的具体问题,我相信 text 这个答案中基于方法的方法要简单得多,同时仍然足够灵活。
#!/usr/bin/env bash
# Create variable with sample input.
IFS= read -r -d '' json <<'EOF'
[
{
"id": 3624,
"created_at": "2016-10-21T20:51:16.000+08:00"
},
{
"id": 3625,
"created_at": "2016-10-22T08:09:16.000+08:00"
},
{
"id": 3626,
"created_at": "2016-10-23T09:19:55.000+08:00"
}
]
EOF
# Use `jq` to select the objects in the array whose .created_at
# property value falls between "2016-10-21:T20:51" and "2016-10-22T08:09"
# and return them as an array (effectively a sub-array of the input).
# (To solve the problem as originally stated, simply pass "2016-10-21"
# and "2016-10-22" instead.)
jq --arg s '2016-10-21T20:51' --arg e '2016-10-22T08:09' '
map(select(.created_at | . >= $s and . <= $e + "z"))
' <<<"$json"
参数--arg s '2016-10-21T20:51'
和--arg e '2016-10-22T08:09'
定义变量$s
(日期+时间范围的开始)和$e
(日期+时间范围的结束) 分别在 jq
脚本中使用。
函数 map()
将封闭的表达式应用于输入数组的所有元素,并将结果也作为数组输出。
函数 select()
接受一个过滤表达式:每个输入对象都根据封闭的表达式求值,只有当表达式求值为 "truthy" 时才会传递输入对象值。
表达式 .created_at | . >= $s and . <= $e + "z"
访问每个输入对象的 created_at
属性 并将其值发送到比较表达式,后者执行 词法 比较,由于日期+时间字符串的格式 - 相当于 时间顺序 比较。
注意附加到范围端点的尾随 "z"
,以确保它与 JSON 字符串中的所有日期+时间字符串相匹配 prefix-匹配端点;例如,端点 2016-10-22T08:09
应匹配 2016-10-22T08:09:01
以及 2016-10-22T08:59
.
这种词法方法允许您根据需要从头开始指定尽可能多的组件,以缩小或扩大日期范围;例如--arg s '2016-10-01' --arg e '2016-10-31'
将匹配 2016 年 10 月整个月的所有条目。
对于更强大的解决方案,最好解析日期以获取其组件并比较这些组件。您可以获得的最接近的是使用 strptime/1
来解析 returns 其组件数组的日期。然后比较组件以检查它是否在范围内。
strptime
returns组成的数组:
year (%Y)
month (%m)
date (%d)
hours (%H)
minutes (%M)
seconds (%S)
day of week (%w)
day of year (%j)
由于您只比较日期,因此比较应该只看前 3 个组成部分。
$ jq --arg s '2016-10-21' --arg e '2016-10-22' '
[($s, $e) | strptime("%Y-%m-%d")[0:3]] as $r
| map(select(
(.created_at[:19] | strptime("%Y-%m-%dT%H:%M:%S")[0:3]) as $d
| $d >= $r[0] and $d <= $r[1]
))
' input.json
由于您 运行 在 Mac 上,我希望这些方法可以在您的构建中使用。您可能需要调整日期格式才能使其按预期工作。正如您在评论中看到的那样,我们必须稍微修改一下才能让它发挥作用。
我有一个像这样的 JSON 字符串 (MacOS):
[{
"id": 3624,
"created_at": "2016-10-21T20:51:16.000+08:00",
},
{
"id": 3625,
"created_at": "2016-10-22T08:09:16.000+08:00",
},
{
"id": 3626,
"created_at": "2016-10-23T09:19:55.000+08:00",
}]
我想 select "created_at" 从“2016-10-21”到“2016-10-22”; 我想得到这样的结果:
[{
"id": 3624,
"created_at": "2016-10-21T20:51:16.000+08:00",
},
{
"id": 3625,
"created_at": "2016-10-22T08:09:16.000+08:00",
}]
有人能给我指出正确的方向吗?
问题已解决 现在,我使用此代码 select 精确到分钟,我希望它对其他人有用:
jq --arg s '2016-10-26T18:16' --arg e '2016-10-27T20:24' '[($s, $e) | strptime("%Y-%m-%dT%H:%M") | mktime] as $r
| map(select(
(.updated_at[:19] | strptime("%Y-%m-%dT%H:%M:%S") | mktime) as $d
| $d >= $r[0] and $d <= $r[1]))' <<< "$requestJson"
根据要求使用命令行 JSON 解析器 jq
:
注意:jq
技术,但对于手头的具体问题,我相信 text 这个答案中基于方法的方法要简单得多,同时仍然足够灵活。
#!/usr/bin/env bash
# Create variable with sample input.
IFS= read -r -d '' json <<'EOF'
[
{
"id": 3624,
"created_at": "2016-10-21T20:51:16.000+08:00"
},
{
"id": 3625,
"created_at": "2016-10-22T08:09:16.000+08:00"
},
{
"id": 3626,
"created_at": "2016-10-23T09:19:55.000+08:00"
}
]
EOF
# Use `jq` to select the objects in the array whose .created_at
# property value falls between "2016-10-21:T20:51" and "2016-10-22T08:09"
# and return them as an array (effectively a sub-array of the input).
# (To solve the problem as originally stated, simply pass "2016-10-21"
# and "2016-10-22" instead.)
jq --arg s '2016-10-21T20:51' --arg e '2016-10-22T08:09' '
map(select(.created_at | . >= $s and . <= $e + "z"))
' <<<"$json"
参数
--arg s '2016-10-21T20:51'
和--arg e '2016-10-22T08:09'
定义变量$s
(日期+时间范围的开始)和$e
(日期+时间范围的结束) 分别在jq
脚本中使用。函数
map()
将封闭的表达式应用于输入数组的所有元素,并将结果也作为数组输出。函数
select()
接受一个过滤表达式:每个输入对象都根据封闭的表达式求值,只有当表达式求值为 "truthy" 时才会传递输入对象值。表达式
.created_at | . >= $s and . <= $e + "z"
访问每个输入对象的created_at
属性 并将其值发送到比较表达式,后者执行 词法 比较,由于日期+时间字符串的格式 - 相当于 时间顺序 比较。注意附加到范围端点的尾随
"z"
,以确保它与 JSON 字符串中的所有日期+时间字符串相匹配 prefix-匹配端点;例如,端点2016-10-22T08:09
应匹配2016-10-22T08:09:01
以及2016-10-22T08:59
.这种词法方法允许您根据需要从头开始指定尽可能多的组件,以缩小或扩大日期范围;例如
--arg s '2016-10-01' --arg e '2016-10-31'
将匹配 2016 年 10 月整个月的所有条目。
对于更强大的解决方案,最好解析日期以获取其组件并比较这些组件。您可以获得的最接近的是使用 strptime/1
来解析 returns 其组件数组的日期。然后比较组件以检查它是否在范围内。
strptime
returns组成的数组:
year (%Y)
month (%m)
date (%d)
hours (%H)
minutes (%M)
seconds (%S)
day of week (%w)
day of year (%j)
由于您只比较日期,因此比较应该只看前 3 个组成部分。
$ jq --arg s '2016-10-21' --arg e '2016-10-22' '
[($s, $e) | strptime("%Y-%m-%d")[0:3]] as $r
| map(select(
(.created_at[:19] | strptime("%Y-%m-%dT%H:%M:%S")[0:3]) as $d
| $d >= $r[0] and $d <= $r[1]
))
' input.json
由于您 运行 在 Mac 上,我希望这些方法可以在您的构建中使用。您可能需要调整日期格式才能使其按预期工作。正如您在评论中看到的那样,我们必须稍微修改一下才能让它发挥作用。