Json.Decode: 提取列表项并 flatten/merge 到记录
Json.Decode: Extract list item and flatten/merge it into record
我想将一些 JSON(使用 inner_hits 的 Elasticsearch 搜索结果)解析为平面记录,但记录的某些字段应该来自列表中的项目,而列表又位于嵌套对象:
{
"_index": "test",
"_type": "doc",
"_id": "AUG.02.013.1320.02630.0",
"_score": null,
"_routing": "1",
"_source": {
"child_mgrpid": "1.1",
"child_varia": "blabla",
"type": "child",
"my_join_field": {
"name": "child",
"parent": "AUG.02.013.1320"
},
"@version": "1",
"@timestamp": "2020-01-12T16:45:11.302Z",
},
"inner_hits": {
"prnt": {
"hits": {
"total": 1,
"max_score": null,
"hits": [
{
"_index": "test",
"_type": "doc",
"_id": "AUG.02.013.1320",
"_score": null,
"_routing": "1",
"_source": {
"pt_archiv": "",
"pt_id": "AUG.02.013.1320",
"pt_titel": "",
"pt_l_id": "AUG.02.013",
"pt_l_name": "Johann Christoph von Freyberg-Eisenberg"
"pt_t_id": "AUG",
"pt_t_kurzform": "AUG",
"type": "parent",
"my_join_field": {
"name": "parent"
},
"@version": "1",
"@timestamp": "2020-01-12T16:45:08.470Z",
},
"sort": [
"AUG"
]
}
]
}
}
}
}
(实际上,数据字段比示例中的多,所以我不能使用 Decoder.mapX
函数。)我肯定知道 entry/parent 在inner_hits.prnt.hits.hits
列表,我想获取它的 _source
字段并将它们与 "main" 对象中的字段一起展平到记录中,其类型定义如下所示:
type alias Child =
{ grp_id : String
, varia : String
, pt_archive : String
, pt_id : String
, pt_title : String
, pt_l_id : String
, pt_l_name : String
, pt_t_id : String
, pt_t_shortLabel : String
}
这是我目前拥有的解码器:
type alias Parent =
{ pt_archive : String
, pt_id : String
, pt_title : String
, pt_l_id : String
, pt_l_name : String
, pt_t_id : String
, pt_t_shortLabel : String
}
childHitDecoder : Decoder Child
childHitDecoder =
Json.Decode.succeed Child
|> Json.Decode.Pipeline.requiredAt [ "_source", "child_mgrp_id" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "child_varia" ] Json.Decode.string
|> Json.Decode.Pipeline.custom (Json.Decode.at [ "inner_hits", "prnt", "hits", "hits" ] (firstElementDecoder parentInnerHitDecoder) )
firstElementDecoder : Json.Decode.Decoder a -> Json.Decode.Decoder a
firstElementDecoder baseDecoder =
Json.Decode.list baseDecoder
|> Json.Decode.map List.head
|> Json.Decode.andThen (Maybe.map Json.Decode.succeed >> Maybe.withDefault (Json.Decode.fail "Empty list"))
parentInnerHitDecoder : Decoder Parent
parentInnerHitDecoder =
Json.Decode.succeed Parent
|> Json.Decode.Pipeline.requiredAt [ "_source", "archiv" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "id" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "titel" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "lah_id" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "lah_name" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "ter_id" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "ter_kurzform" ] Json.Decode.string
(firstElementDecoder
来自 ,我想用它取消列出 inner_hits 列表项。)
使用这样的设置,我的 childHitDecoder
的最后一行给出了一个错误:
This function cannot handle the argument sent through the (|>) pipe:
482| Json.Decode.succeed Child
483| |> Json.Decode.Pipeline.requiredAt [ "_source", "child_mgrp_id" ] Json.Decode.string
484| |> Json.Decode.Pipeline.requiredAt [ "_source", "child_varia" ] Json.Decode.string
485| |> Json.Decode.Pipeline.custom (Json.Decode.at [ "inner_hits", "prnt", "hits", "hits" ] (firstElementDecoder parentInnerHitDecoder) )
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The argument is:
Decoder
(
String
-> String
-> String
-> String
-> String
-> String
-> String
-> Child
)
But (|>) is piping it to a function that expects:
Decoder (Parent -> b)
Hint: It looks like it takes too many arguments. I see 6 extra.
我已经成功地使用 Decode.Pipeline.custom
将嵌套的 JSON 对象解码为其他地方的平面榆树记录,但是,显然,将其与此处的取消列表结合起来超出了我的范围。
这让我困惑了几天,我也尝试过将字段束与 Decode.map
组合,但也失败了。我不太了解 Decode.andThen
or Decode.lazy
看他们是否可以在这里提供帮助,如果有任何帮助,我将不胜感激。
使用上面列出的 json 对象,以下应该有效:
firstPtDecoder : String -> Json.Decode.Decoder String
firstPtDecoder field =
Json.Decode.map (Maybe.withDefault "" << List.head) <|
Json.Decode.at [ "inner_hits", "prnt", "hits", "hits" ] <|
Json.Decode.list (Json.Decode.at [ "_source", field ] Json.Decode.string)
childHitDecoder : Json.Decode.Decoder Child
childHitDecoder =
Json.Decode.succeed Child
|> Json.Decode.Pipeline.requiredAt [ "_source", "child_mgrpid" ] D.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "child_varia" ] D.string
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_archiv")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_id")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_titel")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_l_id")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_l_name")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_t_id")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_t_kurzform")
大部分工作由 firstPtDecoder
完成,它在 "hits" 数组中搜索 field
,returns 在数组的第一个元素中搜索字符串.
我想将一些 JSON(使用 inner_hits 的 Elasticsearch 搜索结果)解析为平面记录,但记录的某些字段应该来自列表中的项目,而列表又位于嵌套对象:
{
"_index": "test",
"_type": "doc",
"_id": "AUG.02.013.1320.02630.0",
"_score": null,
"_routing": "1",
"_source": {
"child_mgrpid": "1.1",
"child_varia": "blabla",
"type": "child",
"my_join_field": {
"name": "child",
"parent": "AUG.02.013.1320"
},
"@version": "1",
"@timestamp": "2020-01-12T16:45:11.302Z",
},
"inner_hits": {
"prnt": {
"hits": {
"total": 1,
"max_score": null,
"hits": [
{
"_index": "test",
"_type": "doc",
"_id": "AUG.02.013.1320",
"_score": null,
"_routing": "1",
"_source": {
"pt_archiv": "",
"pt_id": "AUG.02.013.1320",
"pt_titel": "",
"pt_l_id": "AUG.02.013",
"pt_l_name": "Johann Christoph von Freyberg-Eisenberg"
"pt_t_id": "AUG",
"pt_t_kurzform": "AUG",
"type": "parent",
"my_join_field": {
"name": "parent"
},
"@version": "1",
"@timestamp": "2020-01-12T16:45:08.470Z",
},
"sort": [
"AUG"
]
}
]
}
}
}
}
(实际上,数据字段比示例中的多,所以我不能使用 Decoder.mapX
函数。)我肯定知道 entry/parent 在inner_hits.prnt.hits.hits
列表,我想获取它的 _source
字段并将它们与 "main" 对象中的字段一起展平到记录中,其类型定义如下所示:
type alias Child =
{ grp_id : String
, varia : String
, pt_archive : String
, pt_id : String
, pt_title : String
, pt_l_id : String
, pt_l_name : String
, pt_t_id : String
, pt_t_shortLabel : String
}
这是我目前拥有的解码器:
type alias Parent =
{ pt_archive : String
, pt_id : String
, pt_title : String
, pt_l_id : String
, pt_l_name : String
, pt_t_id : String
, pt_t_shortLabel : String
}
childHitDecoder : Decoder Child
childHitDecoder =
Json.Decode.succeed Child
|> Json.Decode.Pipeline.requiredAt [ "_source", "child_mgrp_id" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "child_varia" ] Json.Decode.string
|> Json.Decode.Pipeline.custom (Json.Decode.at [ "inner_hits", "prnt", "hits", "hits" ] (firstElementDecoder parentInnerHitDecoder) )
firstElementDecoder : Json.Decode.Decoder a -> Json.Decode.Decoder a
firstElementDecoder baseDecoder =
Json.Decode.list baseDecoder
|> Json.Decode.map List.head
|> Json.Decode.andThen (Maybe.map Json.Decode.succeed >> Maybe.withDefault (Json.Decode.fail "Empty list"))
parentInnerHitDecoder : Decoder Parent
parentInnerHitDecoder =
Json.Decode.succeed Parent
|> Json.Decode.Pipeline.requiredAt [ "_source", "archiv" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "id" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "titel" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "lah_id" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "lah_name" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "ter_id" ] Json.Decode.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "ter_kurzform" ] Json.Decode.string
(firstElementDecoder
来自
使用这样的设置,我的 childHitDecoder
的最后一行给出了一个错误:
This function cannot handle the argument sent through the (|>) pipe:
482| Json.Decode.succeed Child
483| |> Json.Decode.Pipeline.requiredAt [ "_source", "child_mgrp_id" ] Json.Decode.string
484| |> Json.Decode.Pipeline.requiredAt [ "_source", "child_varia" ] Json.Decode.string
485| |> Json.Decode.Pipeline.custom (Json.Decode.at [ "inner_hits", "prnt", "hits", "hits" ] (firstElementDecoder parentInnerHitDecoder) )
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The argument is:
Decoder
(
String
-> String
-> String
-> String
-> String
-> String
-> String
-> Child
)
But (|>) is piping it to a function that expects:
Decoder (Parent -> b)
Hint: It looks like it takes too many arguments. I see 6 extra.
我已经成功地使用 Decode.Pipeline.custom
将嵌套的 JSON 对象解码为其他地方的平面榆树记录,但是,显然,将其与此处的取消列表结合起来超出了我的范围。
这让我困惑了几天,我也尝试过将字段束与 Decode.map
组合,但也失败了。我不太了解 Decode.andThen
or Decode.lazy
看他们是否可以在这里提供帮助,如果有任何帮助,我将不胜感激。
使用上面列出的 json 对象,以下应该有效:
firstPtDecoder : String -> Json.Decode.Decoder String
firstPtDecoder field =
Json.Decode.map (Maybe.withDefault "" << List.head) <|
Json.Decode.at [ "inner_hits", "prnt", "hits", "hits" ] <|
Json.Decode.list (Json.Decode.at [ "_source", field ] Json.Decode.string)
childHitDecoder : Json.Decode.Decoder Child
childHitDecoder =
Json.Decode.succeed Child
|> Json.Decode.Pipeline.requiredAt [ "_source", "child_mgrpid" ] D.string
|> Json.Decode.Pipeline.requiredAt [ "_source", "child_varia" ] D.string
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_archiv")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_id")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_titel")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_l_id")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_l_name")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_t_id")
|> Json.Decode.Pipeline.custom (firstPtDecoder "pt_t_kurzform")
大部分工作由 firstPtDecoder
完成,它在 "hits" 数组中搜索 field
,returns 在数组的第一个元素中搜索字符串.