首页 > 解决方案 > 如何使用 Ramda 通过 id 查找和注入外来对象?

问题描述

我有一些对象集合,它们之间具有基本的一对多关系。我的目标是编写一个函数(或必要时可以组合的函数),以便将外部 ID 字段解析/注入到外部对象。

例如,我有以下对象:

const store = {
  users: [
    {
      teamId: 'team-1',
      name: 'user 1',
    },
    {
      teamId: 'team-2',
      name: 'user 2',
    },
  ],
  teams: [
    {
      id: 'team-1',
      regionId: 'region-1',
      name: 'Team 1',
    },
    {
      id: 'team-2',
      regionId: 'region-2',
      name: 'Team 2',
    }
  ],
  regions: [
    {
      id: 'region-1',
      name: 'Region 1',
    },
    {
      id: 'region-2',
      name: 'Region 2',
    },
  ],
}

我的目标是将其解决为以下问题:

const users = [
    {
      teamId: 'team-1',
      name: 'user 1',
      team: {
        id: 'team-1',
        regionId: 'region-1',
        region: {
          id: 'region-1',
          name: 'Region 1',
        },
        name: 'Team 1',
      }
    },
    // ...and so on
]

我离解决第一级不远了:

const findObject = (collection, idField = 'id') => id => R.find(R.propEq(idField, id), R.prop(collection, store))
const findTeam = findObject('teams')
const findRegion = findObject('regions')
const inject = field => R.useWith(
  R.merge,
  [R.objOf(field), R.identity]
)
const injectTeam = R.useWith(
  inject('team'),
  [findTeam]
)
const injectRegion = R.useWith(
  inject('region'),
  [findRegion]
)

R.map(injectTeam('team-1'))(store.users)

但这对我来说太过分了,到目前为止,我只用 Ramda 做了更简单的事情。理想情况下,该解决方案将允许我以某种方式组合注入器功能,因此解决更深层次的问题是可选的。

标签: javascriptfunctional-programmingramda.js

解决方案


我正在使用 R.converge 提取users并创建 and 的查找teamsregions然后通过从查找中users替换teamId为团队来映射 ,并在内部对该区域执行相同操作。

const { pipe, pick, map, indexBy, prop, converge, assoc, identity, flip, evolve } = R

// create a lookup of id -> object from teams and regions
const createLookup = pipe(
  pick(['teams', 'regions']),
  map(indexBy(prop('id')))
)

// add the value from the idPath in the lookup to the resultPath of the current object 
const injectFromLookup = (idKey, lookup, resultKey) => 
  converge(assoc(resultKey), [
    pipe(
      prop(idKey),
      flip(prop)(lookup),
    ),
    identity,
  ])

// extract users, create lookup, and map users to the required form
const inject = converge(
  (users, lookup) => map(
    pipe(
      injectFromLookup('teamId', prop('teams', lookup), 'team'),
      evolve({
        team: injectFromLookup('regionId', prop('regions', lookup), 'region')
      })
    )
  , users),
  [prop('users'), createLookup],
)

const store = {"users":[{"teamId":"team-1","name":"user 1"},{"teamId":"team-2","name":"user 2"}],"teams":[{"id":"team-1","regionId":"region-1","name":"Team 1"},{"id":"team-2","regionId":"region-2","name":"Team 2"}],"regions":[{"id":"region-1","name":"Region 1"},{"id":"region-2","name":"Region 2"}]}

console.log(inject(store))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>


推荐阅读