求助:编写Jolt Spec实现嵌套JSON转换输出扁平化数组
Jolt多层嵌套JSON库存数据扁平化方案
问题表现
进行JSON结构转换时,嵌套的库存层级字段未按预期打平,同存储位置下的多条库存数据被聚合为单对象下的数组字段,未实现「单条库存对应一个独立输出对象」的扁平化效果。
输入样例结构
输入JSON包含三层嵌套数组:根节点下的存储位置数组data.storageLocations,每个存储位置下包含库存数组stocks,每个库存条目下又包含数量数组quantity,同时存在全局元数据、商品公共字段需要下沉到每一条扁平化后的库存记录中。
{ "metadata": { "timestamp": "XXXXX" }, "data": { "product": { "id": "XXXXX" }, "storageLocations": [ { "id": "XXXXX", "stocks": [ { "stockStatus": "XXXXX", "quantity": [{"uom": "XXXXX","isoUom": "XXXXX","amount": "XXXXX"}] }, { "stockStatus": "XXXXX", "quantity": [{"uom": "XXXXX","isoUom": "XXXXX","amount": "XXXXX"}] }, { "stockStatus": "XXXXX", "quantity": [{"uom": "XXXXX","isoUom": "XXXXX","amount": "XXXXX"}] } ], "dateModified": "XXXXX" }, { "id": "XXXXX", "stocks": [ { "stockStatus": "XXXXX", "quantity": [{"uom": "XXXXX","isoUom": "XXXXX","amount": "XXXXX"}] }, { "stockStatus": "XXXXX", "quantity": [{"uom": "XXXXX","isoUom": "XXXXX","amount": "XXXXX"}] }, { "stockStatus": "XXXXX", "quantity": [{"uom": "XXXXX","isoUom": "XXXXX","amount": "XXXXX"}] } ], "dateModified": "XXXXX" }, { "id": "XXXXX", "stocks": [ { "stockStatus": "XXXXX", "quantity": [{"uom": "XXXXX","isoUom": "XXXXX","amount": "XXXXX"}] }, { "stockStatus": "XXXXX", "quantity": [{"uom": "XXXXX","isoUom": "XXXXX","amount": "XXXXX"}] }, { "stockStatus": "XXXXX", "quantity": [{"uom": "XXXXX","isoUom": "XXXXX","amount": "XXXXX"}] } ], "dateModified": "XXXXX" } ], "dateModified": "XXXXX", "temporaryNegativeStock": "XXXXX" } }
原有Spec问题
原有Spec直接在最内层quantity层级使用[&5]作为输出索引,该索引仅对应存储位置的数组下标,同个存储位置下的3条库存数据都会被写入同一个输出对象的同路径下,Jolt默认会将同路径多值合并为数组,最终导致库存字段全部变为数组形式。
原有错误Spec:
[ { "operation": "shift", "spec": { "data": { "storageLocations": { "*": { "@(3,metadata.timestamp)": "[&1].LastUpdated", "@(2,product.id)": "[&1].MaterialCode", "@(2,product.baseUoM)": "[&1].BaseUoM", "@(2,product.isoBaseUom)": "[&1].ISOBaseUoM", "@(2,location.id)": "[&1].LocationId", "@(id)": "[&1].StorageLocationId", "@(dateModified)": "[&1].StorageLocationLastUpdated", "stocks": { "*": { "quantity": { "*": { "@(amount)": "[&5].StockAmount", "@(isoUom)": "[&5].StockISOUoM", "@(uom)": "[&5].StockUoM", "@(2,stockStatus)": "[&5].StockStatus" } } } } } } } } } ]
错误输出表现
输出数组长度与存储位置数量一致(共3个对象),每个对象内的库存字段均为长度3的数组,未打平到单条库存粒度。
[ { "LastUpdated": "XXXXX", "MaterialCode": "na-XXXXX", "StorageLocationId": "XXXXX", "StorageLocationLastUpdated": "XXXXX", "StockAmount": ["0.000","0.000","0.000"], "StockISOUoM": ["XXXXX","XXXXX","XXXXX"], "StockUoM": ["XXXXX","XXXXX","XXXXX"], "StockStatus": ["XXXXX","XXXXX","XXXXX"] }, { "LastUpdated": "XXXXX", "MaterialCode": "na-XXXXX", "StorageLocationId": "XXXXX", "StorageLocationLastUpdated": "XXXXX", "StockAmount": ["0.000","0.000","0.000"], "StockISOUoM": ["XXXXX","XXXXX","XXXXX"], "StockUoM": ["XXXXX","XXXXX","XXXXX"], "StockStatus": ["XXXXX","XXXXX","XXXXX"] }, { "LastUpdated": "XXXXX", "MaterialCode": "na-XXXXX", "StorageLocationId": "XXXXX", "StorageLocationLastUpdated": "XXXXX", "StockAmount": ["0.000","0.000","0.000"], "StockISOUoM": ["XXXXX","XXXXX","XXXXX"], "StockUoM": ["XXXXX","XXXXX","XXXXX"], "StockStatus": ["XXXXX","XXXXX","XXXXX"] } ]
正确实现方案
采用两步shift转换,第一步先归集所有层级数据到临时路径,避免索引计算混乱;第二步遍历到最内层库存条目,使用自增索引生成独立输出对象,确保每条库存对应一条记录。
可用的Jolt Spec如下:
[ { "operation": "shift", "spec": { "metadata": { "timestamp": "tmp.timestamp" }, "data": { "product": { "id": "tmp.productId", "baseUoM": "tmp.baseUoM", "isoBaseUom": "tmp.isoBaseUom" }, "storageLocations": { "*": { "id": "tmp.locations[&1].id", "dateModified": "tmp.locations[&1].dateModified", "stocks": { "*": { "stockStatus": "tmp.locations[&3].stocks[&1].stockStatus", "quantity": { "*": { "uom": "tmp.locations[&5].stocks[&3].uom", "isoUom": "tmp.locations[&5].stocks[&3].isoUom", "amount": "tmp.locations[&5].stocks[&3].amount" } } } } } } } } }, { "operation": "shift", "spec": { "tmp": { "locations": { "*": { "stocks": { "*": { "@(4,timestamp)": "[#4].LastUpdated", "@(4,productId)": "[#4].MaterialCode", "@(4,baseUoM)": "[#4].BaseUoM", "@(4,isoBaseUom)": "[#4].ISOBaseUoM", "@(2,id)": "[#4].StorageLocationId", "@(2,dateModified)": "[#4].StorageLocationLastUpdated", "amount": "[#4].StockAmount", "isoUom": "[#4].StockISOUoM", "uom": "[#4].StockUoM", "stockStatus": "[#4].StockStatus" } } } } } } } ]
输出效果
最终输出数组长度为「存储位置数 * 每个存储位置下的库存条目数」,每个对象为单条库存的全量扁平化数据,所有字段均为单值,不存在数组聚合问题。
内容的提问来源于stack exchange,提问作者Thiyagaraj Narayanan
相关产品推荐
相关产品推荐

