javascript - 使用通用键重构对象/数组

标签 javascript data-structures lodash

我正在构建一个工具,允许用户从通用源(具有通用结构)获取数据并重新映射属性以匹配我的 API。

  1. 用户将输入源 URL(REST API 或 JSON);
  2. 用户将输入基于 JSON 的 DTO 指令

DTO 将是这样的 JSON:

{
  "data.collection.name": "section.title",
  "just.an.example": "data.foo",
}

当源提供具有这种结构的数据时:

{
  "data": {
    "foo": "bar",
    "collection": {
      "totalCount": 123,
      "title": "Best sellers",
    }
  }
}

该功能会将值重新映射到:

{
  "section": {
     "title": "Best sellers"
  },
  "just": {
    "an": {
      "example": "bar"
    }
  }
}

我可以使用 lodash getset 方法实现这一点,算法如下:

const data = {
  foo: "bar",
  collection: {
    title: "BestSellers",
  },
  just: {
    an: {
      example: "bar",
    },
  },
  nodes: {
    edges: [
      {
        title: "Orange juice",
        slug: "orange-juice",
      },
      {
        title: "Apple juice",
        slug: "apple-juice",
      },
    ],
  },
};

let transformed = {};

const transformer = {
  "collection.title": "section.title",
  "just.an.example": "foo",
};

Object.keys(transformer).forEach((key) => {
  const value = _.get(data, key);
  const path = transformer[key];

  _.set(transformed, path, value);
});

console.log(transformed);

现在我需要获得相同的结果,但需要使用数组属性(如 nodes.edges)。

用户 DTO JSON 看起来像这样(不是必需的,但很理想):

{
  "data.collection.name": "section.title",
  "nodes.edges.title": "products.title",
  "nodes.edges.slug": "products.seo.slug",
}

将生成此输出:

{
  "section": {
    "title": "BestSellers"
  },
  "products": [
    {
      "title": "Orange Juice",
      "seo": {
         "slug": "orange-juice"
      }
    },
    {
      "title": "Apple Juice",
      "seo": {
         "slug": "apple-juice"
      }
    }
  ]
}

最佳答案

对于源数组的位置没有歧义,但对于目标数组的确切位置存在歧义。因此[]放在目标映射中,表示数组位置。

const data = { foo: "bar", collection: { title: "BestSellers", }, just: { an: { example: "bar", }, }, nodes: { edges: [ { title: "Orange juice", slug: "orange-juice", }, { title: "Without a slug" }, { slug: "without-a-title" }, { title: "Apple juice", slug: "apple-juice", }, ], }, };
const transformer = {
  "collection.title": "section.title",
  "nodes.edges.title": "products.items[].title",
  "nodes.edges.slug": "products.items[].seo.slug",
};

function getAtPath(path, data) {
  let s = path.split('.');
  let v = data[s[0]];
  if(s.length===1) return v;
  let q = s.slice(1).join('.');
  return Array.isArray(v) ? v.map(i=>getAtPath(q, i)) : getAtPath(q, v);
}
function setAtPath(path, value, dest) {
  let s = path.split('.'), d = dest;
  for(let [i,e] of s.entries()) {
    if(i === s.length-1) d[e] = value;
    else {
      if(e.endsWith('[]')) {
        e = e.substring(0, e.length-2);
        value.forEach((j,k) => setAtPath(`${k}.${s.slice(i+1).join('.')}`, j, d[e]??=[]));
        break;
      }
      else d = d[e]??={};
    }
  }
}
function transform(transformer, data) {
  let r = {};
  Object.entries(transformer).forEach(([x,y])=>setAtPath(y,getAtPath(x, data),r));
  return r;
}
console.log(transform(transformer, data));

关于javascript - 使用通用键重构对象/数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74256072/

相关文章:

javascript - 带有 Javascript 的 Firebase Auth 应该使用 HTTPS

algorithm - 用于合并唯一键的最快 KV 数据结构?

javascript - 使用特定步骤对数组的某些元素进行打乱

javascript - 访问 nw.js 中的文件属性

javascript - 根据 X 和 Y 坐标确定事件三 Angular 形

javascript - 页面的打印版本。我想附加相关链接的完整网址

java - 列表列表的笛卡尔积

mysql - 如何在mysql中构建一个用于检测过期许可证的表?

javascript - Lodash 去抖不起作用

javascript - 使用 browserify 需要 jQuery 和 lodash