我正在构建一个工具,允许用户从通用源(具有通用结构)获取数据并重新映射属性以匹配我的 API。
- 用户将输入源 URL(REST API 或 JSON);
- 用户将输入基于 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 get
和 set
方法实现这一点,算法如下:
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/