[英]How to update value of a key present at any level in a JSON using Ramda?
有沒有辦法找到一個鍵的值,它可以出現在任何對象下的任何級別,並使用Ramda更新它?
例如,
JSON-1
{
"query": {
"boundary": {
"type": "polygon",
"coordinates": "[[-85.33604,35.055749],[-85.33604,35.07499772909699],[-85.279134,35.07499772909699],[-85.279134,35.055749],[-85.33604,35.055749]]"
}
}
JSON-2
{
"query": {
"nearby": {
"radius": "30mi",
"coordinates": "[-121.40019800,38.55378300]"
}
}
}
在這兩個JSON中,我想做的事情如下:
query.nearby.coordinates = JSON.parse(query.nearby.coordinates)
和
query.boundary.coordinates = JSON.parse(query.boundary.coordinates)
具有單一功能。
另一個選擇是定義一個可以處理更新值的鏡頭。
第一種方法將假設存在有限數量的已知路徑,可以找到坐標。
// Creates a lens that accepts a list of paths and chooses the first // matching path that exists in the target object const somePathLens = paths => toFunctor => target => { const path = R.find( p => R.pathSatisfies(x => x != null, p, target), paths ) return R.map( value => R.assocPath(path, value, target), toFunctor(R.path(path, target)) ) } // R.over can then be used with JSON.parse to parse the first // matching path that is found. const parseCoords = R.over( somePathLens([ ['query', 'boundary', 'coordinates'], ['query', 'nearby', 'coordinates'] ]), JSON.parse ) console.log(parseCoords({ "query": { "boundary": { "type": "polygon", "coordinates": "[[-85.33604,35.055749],[-85.33604,35.07499772909699],[-85.279134,35.07499772909699],[-85.279134,35.055749],[-85.33604,35.055749]]" } } })) console.log(parseCoords({ "query": { "nearby": { "radius": "30mi", "coordinates": "[-121.40019800,38.55378300]" } } }))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
如果實際路徑未知且您只需要通過給定鍵找到第一個值,則可以使用第二種方法。
// Recursively search for the given key in an object, returning the // first matching path if found. const findKeyInPath = (keyToFind, obj) => { const findKeyInPath_ = o => R.has(keyToFind, o) // if found, return this key as the path ? [keyToFind] // otherwise find all keys with objects and recursively // call this function. : R.reduceRight((k, acc) => { // find either the subpath of this key, or the subpath // found in the remaining keys const subPath = R.when(R.isEmpty, _ => acc, findKeyInPath_(o[k])) // if the subpath contains a key, prepend it with the // current key, otherwise return the empty list return R.unless(R.isEmpty, R.prepend(k), subPath) }, [], R.filter(k => R.propIs(Object, k, o), R.keys(o))) return findKeyInPath_(obj) } // Create a lens that recursively searches for the first matching // key within a target object. const someKeyLens = key => toFunctor => target => { // find the path using our new `findKeyInPath` function const path = findKeyInPath(key, target) return R.map( value => R.assocPath(path, value, target), toFunctor(R.path(path, target)) ) } const parseCoords = R.over( someKeyLens('coordinates'), JSON.parse ) console.log(parseCoords({ "query": { "boundary": { "type": "polygon", "coordinates": "[[-85.33604,35.055749],[-85.33604,35.07499772909699],[-85.279134,35.07499772909699],[-85.279134,35.055749],[-85.33604,35.055749]]" } } })) console.log(parseCoords({ "query": { "nearby": { "radius": "30mi", "coordinates": "[-121.40019800,38.55378300]" } } }))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
值得一提的是,如果保證在目標對象中找到路徑,則這些只是有效的鏡頭,否則行為是不確定的。
一種方法是遍歷對象樹,並嘗試解析您找到的任何字符串作為JSON。
const parseNestedJSON = R.cond([
[R.is(String), R.tryCatch(JSON.parse, R.nthArg(1))],
[R.is(Object), obj => R.map(parseNestedJSON, obj)],
[R.T, R.identity],
])
請注意,這可能會進行一些不需要的轉換,例如將{foo: '1'}
轉換為{foo: 1}
(字符串轉換為數字)。
僅定位稱為coordinates
嵌套鍵可能更安全:
const parseNestedJSON = R.cond([
[R.has('coordinates'), R.over(R.lensProp('coordinates'), JSON.parse)],
[R.is(Object), obj => R.map(parseNestedJSON, obj)],
[R.T, R.identity],
])
編輯:如果coordinates
可能不是json,您也可以在此處使用tryCatch
。
[R.has('coordinates'), R.over(R.lensProp('coordinates'), R.tryCatch(JSON.parse, R.nthArg(1)))]
用法:
parseNestedJSON({"nearby": {"coordinates": "[-121.40019800,38.55378300]"}})
=> { nearby: { coordinates: [ -121.400198, 38.553783 ] } }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.