简体   繁体   English

更新 object 值 Ramda

[英]Update object value Ramda

In previous question I tried to group arrays by parent ids and then remove them from each object - Group arrays by parent ids object Ramda . In previous question I tried to group arrays by parent ids and then remove them from each object - Group arrays by parent ids object Ramda .

But now I have a new issue.但现在我有一个新问题。 For example I want to update title in object with id 12.例如,我想用 id 12 更新 object 中的标题。

My data model:我的数据 model:

const stuff = {
  "31": [
    {
      "id": "11",
      "title": "ramda heeeelp"
    },
    {
      "id": "12",
      "title": "ramda 123"
    }
  ],
  "33": [
    {
      "id": "3",
      "title": "..."
    }
  ],
  "4321": [
    {
      "id": "1",
      "title": "hello world"
    }
  ]
}

Attempts:尝试:

const alter = (id, key, value) => pipe(
  values,
  flatten,
  update(...) // <= end of my attempts
  // then group again
)

alter('12', 'title', 'new heading 123')(stuff)

You can use lenses here:您可以在此处使用镜头

  1. Over: https://ramdajs.com/docs/#over结束: https://ramdajs.com/docs/#over
  2. Set: https://ramdajs.com/docs/#set设置: https://ramdajs.com/docs/#set

 const titleLens = R.curry((key, id, data) => R.lensPath([ key, R.findIndex(R.whereEq({ id }), R.propOr([], key, data)), 'title' ])); // ---- const stuff = { "31": [ { "id": "11", "title": "ramda heeeelp" }, { "id": "12", "title": "ramda 123" } ], "33": [ { "id": "3", "title": "..." } ], "4321": [ { "id": "1", "title": "hello world" } ] } const title3111 = titleLens('31', '11', stuff); const result = R.set(title3111, 'DID RAMDA HELP YOU?', stuff); console.log('result', result);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>

I think this would be best done with a custom lens .我认为这最好用定制lens来完成。 Here I write a lens creator ( idInObjLens ) that focuses on the object with the correct id, regardless of what group it falls in. Then I write myLens to accept an id and a property name and return you a lens that focuses on that property of the object.在这里,我编写了一个镜头创建器 ( idInObjLens ),它专注于具有正确 id 的 object,无论它属于哪个组。然后我编写myLens来接受一个 id 和一个属性名称,并返回一个专注于该属性的镜头object。

With those, we can use Ramda's view , set , and over to see the value, set the value, or update the value with a function:有了这些,我们可以使用 Ramda 的viewsetover来查看值、设置值或使用 function 更新值:

 const idInObjLens = (id) => lens ( (obj) => { let index = -1 const child = find (value => (index = findIndex (propEq ('id', id), value)) > -1, values (obj) ) if (child) return child [index] }, (val, obj) => { let index = -1 const [key, value] = find (([key, value]) => (index = findIndex (propEq ('id', id), value)) > -1, toPairs (obj) ) return assoc (key, update (index, val, value), obj) }, ) const myLens = (id, key) => compose (idInObjLens (id), lensProp (key)) const stuff = {"31": [{"id": "11", "title": "ramda heeeelp"}, {"id": "12", "title": "ramda 123"}], "33": [{"id": "3", "title": "..."}], "4321": [{"id": "1", "title": "hello world"}]}; [ view (myLens ('12', 'title'), stuff), set (myLens ('3', 'title'), 'new heading 123', stuff), over (myLens ('1', 'title'), toUpper, stuff), ].forEach (x => console.log (x))
 .as-console {background-color:black;important: color;lime.}:as-console-wrapper {max-height;100%:important; top:0;}
 <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script> <script>const {lens, find, findIndex, propEq, values, toPairs, assoc, update, compose, lensProp, view, set, over, toUpper } = R</script>

Note that the set and over will only work if that id actually exists.请注意,只有当该 id 实际存在时, setover才会起作用。 You might want to check using view first.您可能需要先使用view进行检查。

myLens is simple; myLens很简单; it's just how lens composition works.这就是镜头构图的工作原理。 (Notice that it seems to flow backward from regular compose; the technical reasons are interesting, but beyond the scope of an SO answer.) But idInObjLens is more complex. (请注意,它似乎从常规撰写中倒流; 技术原因很有趣,但超出了 SO 答案的 scope。)但idInObjLens更复杂。 As with all lenses, it takes a getter and a setter.与所有镜头一样,它需要一个 getter 和一个 setter。 Both of them simultaneously find the object key that contains the item with the id and the index of that key in the array associated with that object key.他们两个同时找到 object 键,该键包含与该 object 键关联的数组中具有该键的 id 和索引的项目。 The getter simply returns the value. getter 只是简单地返回值。 The setter uses assoc to update the outer object and update to update the array inside it. setter 使用assoc更新外部 object 并update以更新其中的数组。 All other nested objects are simply returned by reference.所有其他嵌套对象都通过引用简单地返回。

This is not code to be proud of.这不是值得骄傲的代码。 It works, and of course that's the main thing.它有效,当然这是主要的。 But I really don't like calculating the array index as a side-effect of the find call.但我真的不喜欢将数组索引计算为find调用的副作用。 Yet calculating it a second time just seems overkill.然而,再次计算它似乎有点过分了。 I also don't really like the name idInObjLens and I always feel that if I don't have a good name, I'm missing something fundamental.我也不太喜欢idInObjLens这个名字,而且我总是觉得如果我没有一个好名字,我就会错过一些基本的东西。 (I don't have the same objection to myLens , as I assume you will have a better name for this for your use-case.) (我对myLens没有同样的反对意见,因为我认为你会为你的用例有一个更好的名字。)

The big difference between this and the solution from Hitmand is that this lens does not require you to know up-front which key in the outer object holds the item with your id.这与 Hitmand 的解决方案之间的最大区别在于,该镜头不需要您预先知道外部 object 中的哪个键持有您的 ID 项目。 That adds a fair bit of complexity to the solution, but makes its API much more flexible.这给解决方案增加了相当多的复杂性,但使其 API 更加灵活。

You map all array inside properties, and use R.when to evolve all objects with matching id s, and replace the property's ( title in your case) value:您 map 属性内的所有数组,并使用R.when进化所有具有匹配id的对象,并替换属性的(在您的情况下title )值:

 const { curry, map, when, propEq, evolve, always } = R const fn = curry((id, prop, content) => map(map( // map all objects of all properties when( propEq('id', id), // if the id of an object matches evolve({ [prop]: always(content) })) // evolve it's property to the content ) )) const data = {"31":[{"id":"11","title":"ramda heeeelp"},{"id":"12","title":"ramda 123"}],"33":[{"id":"3","title":"..."}],"4321":[{"id":"1","title":"hello world"}]} const result = fn('12', 'title', 'new heading 123')(data) console.log(result);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM