如何使用 vue/javascript 通过多个属性过滤深度嵌套的 json [英] How to filter deeply nested json by multiple attributes with vue/javascript
问题描述
我有一些具有以下结构的 JSON:
I have some JSON with the following structure:
{
"root": {
"Europe": {
"children": [
{
"name": "Germany"
},
{
"name": "England",
"children": [
{
"name": "London",
"search_words": ["city", "capital"],
"children": [
{
"name": "Westminster",
"search_words": ["borough"]
}
]
},
{
"name": "Manchester",
"search_words": ["city"]
}
]
},
{
"name": "France",
"children": [
{
"name": "Paris",
"search_words": ["city", "capital"]
}
]
}
]
},
"North America": {
"children": [
{
"name": "Canada",
"children": [
{
"name": "Toronto"
},
{
"name": "Ottawa"
}
]
},
{
"name": "United States"
}
]
}
}
}
我想根据文本搜索过滤 JSON.我应该能够通过 name
和任何 search_words
进行搜索.最后一个问题是 JSON 可以任意深度,因此需要能够搜索所有级别.
I want to filter the JSON based on a text search. I should be able to search by both the name
and any search_words
. The final problem is that the JSON can be arbitrarily deep so it needs to be able to search through all levels.
我还需要遍历并打印出 HTML 格式的 JSON(使用 Vue),并根据搜索结果进行更新.目前不清楚如何在不知道 JSON 会深入多少层的情况下做到这一点?
I also need to loop through and print out the JSON in HTML (using Vue) and for it to update based on the search. Currently unclear how I can do this without knowing how many levels deep the JSON will go?
任何帮助将不胜感激!
推荐答案
我最近回答了一个类似的问题.我在这里分享它是因为我认为它为这篇文章提供了一个相关的基础.在开始之前,我们必须首先解决输入数据的不规则形状 -
I answered a similar question recently. I'm sharing it here because I think it provides a relevant foundation for this post. Before we begin though, we must first address the irregular shape of your input data -
const data2 =
{ name:"root"
, children:
Array.from
( Object.entries(data.root)
, ([ country, _ ]) =>
Object.assign({ name:country }, _)
)
}
console.log(JSON.stringify(data2, null, 2))
现在我们可以看到 data2
是一个统一的 { name, children: [ ... ]}
形状 -
Now we can see data2
is a uniform { name, children: [ ... ]}
shape -
{
"name": "root",
"children": [
{
"name": "Europe",
"children": [
{ "name": "Germany" },
{
"name": "England",
"children": [
{
"name": "London",
"search_words": [ "city", "capital" ],
"children": [
{
"name": "Westminster",
"search_words": [ "borough" ]
}
]
},
{
"name": "Manchester",
"search_words": [ "city" ]
}
]
},
{
"name": "France",
"children": [
{
"name": "Paris",
"search_words": [ "city", "capital" ]
}
]
}
]
},
{
"name": "North America",
"children": [
{
"name": "Canada",
"children": [
{ "name": "Toronto" },
{ "name": "Ottawa" }
]
},
{ "name": "United States" }
]
}
]
}
现在我们写一个通用的深度优先遍历函数,dft
-
Now we write a generic depth-first traversal function, dft
-
function* dft (t, path = [])
{ for (const _ of t.children ?? [])
yield* dft(_, [...path, t.name ])
yield [path, t]
}
我们的 dft
函数为我们提供了一个 path
到我们输入树中的每个元素 e
,t
-
Our dft
function gives us a path
to each element, e
, in our input tree, t
-
["root","Europe"]
{"name":"Germany"}
["root","Europe","England","London"]
{name:"Westminster", search_words:["borough"]}
["root","Europe","England"]
{name:"London", search_words:["city","capital"], children:[...]}
["root","Europe","England"]
{name:"Manchester", search_words:["city"]}
["root","Europe"]
{name:"England", children:[...]}
["root","Europe","France"]
{name:"Paris", search_words:["city","capital"]}
["root","Europe"]
{name:"France", children:[...]}
["root"]
{name:"Europe", children:[...]}
["root","North America","Canada"]
{name:"Toronto"}
既然我们知道了每个节点的路径,我们可以创建一个 index
,它使用 path
和任何 search_words
来链接回到节点-
Now that we know that path to each of the nodes, we can create an index
which uses the path
and any search_words
to link back to the node -
const index = t =>
Array.from
( dft(t)
, ([path, e]) =>
[ [...path, e.name, ...e.search_words ?? [] ] // all words to link to e
, e // e
]
)
.reduce
( (m, [ words, e ]) =>
insertAll(m, words, e) // update the index using generic helper
, new Map
)
这取决于一个通用的帮助器 insertAll
-
This depends on a generic helper insertAll
-
const insertAll = (m, keys, value) =>
keys.reduce
( (m, k) =>
m.set(k, [ ...m.get(k) ?? [], value ])
, m
)
index
完成后,我们可以为任何搜索词创建快速查找 -
With index
finished, we have a way to create a fast lookup for any search term -
const myIndex =
index(data2)
console.log(myIndex)
Map
{ "Europe" =>
[{"name":"Germany"},{"name":"Westminster",...},{"name":"London",...},{"name":"Manchester",...},{"name":"England"...},{"name":"Manchester",...}]},{"name":"Paris",...},{"name":"France"...},{"name":"Europe"...},{"name":"Manchester",...}]},{"name":"France"...}]}]
, "Germany" =>
[{"name":"Germany"}]
, "England" =>
[{"name":"Westminster",...},{"name":"London",...},{"name":"Manchester",...},{"name":"England"...},{"name":"Manchester",...}]}]
, "London" =>
[{"name":"Westminster",...},{"name":"London",...}]
, "Westminster" =>
[{"name":"Westminster",...}]
, "borough" =>
[{"name":"Westminster",...}]
, "city" =>
[{"name":"London",...},{"name":"Manchester",...},{"name":"Paris",...}]
, "capital" =>
[{"name":"London",...},{"name":"Paris",...}]
, "Manchester" =>
[{"name":"Manchester",...}]
, "France" =>
[{"name":"Paris",...},{"name":"France"...}]
, "Paris" =>
[{"name":"Paris",...}]
, "North America" =>
[{"name":"Toronto"},{"name":"Ottawa"},{"name":"Canada"...},{"name":"United States"},{"name":"North America"...},
{"name":"United States"}]}]
, "Canada" =>
[{"name":"Toronto"},{"name":"Ottawa"},{"name":"Canada"...}]
, "Toronto" =>
[{"name":"Toronto"}]
, "Ottawa" =>
[{"name":"Ottawa"}]
, "United States" =>
[{"name":"United States"}]
}
这应该会突出显示数据中剩余的不一致之处.例如,您有一些节点嵌套在 city
、capital
或 borough
下.另外值得注意的是,我们可能应该在所有索引键上使用 s.toLowerCase()
以便查找可以不区分大小写.这是留给读者的练习.
This should highlight the remaining inconsistencies in your data. For example, you have some nodes nested under city
, capital
, or borough
. Also worth noting that we should probably use s.toLowerCase()
on all of the index keys so that lookups can be case-insensitive. This is an exercise left for the reader.
创建index
很简单,你只需要一次 -
Creating the index
is easy and you only need to do it once -
const myIndex =
index(data2)
您的索引可以根据需要重复使用进行多次查找 -
Your index can be reused for as many lookups as you need -
console.log(myIndex.get("Toronto") ?? [])
console.log(myIndex.get("France") ?? [])
console.log(myIndex.get("Paris") ?? [])
console.log(myIndex.get("Canada") ?? [])
console.log(myIndex.get("Zorp") ?? [])
[{"name":"Toronto"}]
[{"name":"Paris",...},{"name":"France"...}]
[{"name":"Paris",...}]
[{"name":"Toronto"},{"name":"Ottawa"},{"name":"Canada"...}]
[]
在您的 Vue 应用程序中插入结果由您决定.
Inserting the results in you Vue application is left for you.
这篇关于如何使用 vue/javascript 通过多个属性过滤深度嵌套的 json的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!