如何用Lodash搜索含动态键的深层嵌套JSON并返回根对象?
使用Lodash搜索嵌套JSON(含动态键)
嘿,我完全懂你现在的需求——要在嵌套的JSON数据里用Lodash做模糊搜索,还得处理那些动态变化的键,而且只要任意指定位置匹配上,就得返回对应的根对象。我来给你一步步拆解出可行的解决方案:
首先先明确我们要覆盖的三个匹配场景:
- 根对象的
name字段 activities.routines下的动态键名称(比如示例里的"Biking"、"Kayaking")activities.routines.*.details(动态键对应的详情字段)
同时要考虑activities可能是空数组、routines可能是空对象的容错情况。
完整实现代码
function searchText(collection, searchTerm) { // 统一转小写,避免大小写敏感问题 const lowerSearchTerm = searchTerm.toLowerCase(); return _.filter(collection, (rootObj) => { // 1. 检查name字段是否匹配 const nameMatches = _.includes(rootObj.name.toLowerCase(), lowerSearchTerm); // 2. 检查activities嵌套结构中的匹配项 const activitiesMatches = _.some(rootObj.activities, (activity) => { // 先判断当前activity的routines是否有内容,避免空对象报错 if (!_.isEmpty(activity.routines)) { // 检查动态键名称是否匹配 const routineKeyMatches = _.some(_.keys(activity.routines), (key) => _.includes(key.toLowerCase(), lowerSearchTerm) ); // 检查所有routine的details字段是否匹配 const routineDetailsMatches = _.some(activity.routines, (routine) => _.includes(routine.details.toLowerCase(), lowerSearchTerm) ); // 键名或details有一个匹配,就算当前activity符合条件 return routineKeyMatches || routineDetailsMatches; } // 若routines为空,直接返回false return false; }); // 只要name或activities中有任意一个匹配,就保留这个根对象 return nameMatches || activitiesMatches; }); }
代码逻辑拆解
- 统一大小写处理:先把搜索词转成小写,后续所有匹配都用小写对比,彻底解决大小写敏感问题。
- 根对象name匹配:和你之前实现的逻辑一致,用
_.includes判断是否包含搜索词。 - 嵌套结构匹配:
- 用
_.some遍历activities数组,只要数组里有一个activity符合条件,就判定该根对象有效(避免全量遍历提升效率)。 - 对每个activity,先通过
_.isEmpty判断routines是否有内容,跳过空对象的无效遍历。 - 动态键匹配:用
_.keys()提取routines的所有动态键,再用_.some检查是否有键名包含搜索词。 - details字段匹配:直接用
_.some遍历routines的所有值(即每个routine对象),检查details字段是否匹配。
- 用
- 最终判定:只要name或嵌套结构中有任意一个匹配,就将该根对象加入结果集。
使用示例
假设你的数据源是:
const data = [ { "name": "Bob's concourse", "activities": [ { "day": "Monday", "routines": { "Biking": { "details": "won 3 trophies", "type": "road" }, "Kayaking": { "details": "participated in 3 races", "type": "rhythm" } } } ] }, { "name": "Alice's gym", "activities": [] } ];
- 调用
searchText(data, "races"):返回第一个根对象(Kayaking的details匹配) - 调用
searchText(data, "biking"):返回第一个根对象(动态键名"Biking"匹配) - 调用
searchText(data, "bob"):返回第一个根对象(name字段匹配) - 调用
searchText(data, "swim"):返回空数组(无匹配项)
额外容错提示
如果routines可能是undefined(而非空对象),可以把判断条件改成:
if (_.has(activity, 'routines') && !_.isEmpty(activity.routines))
进一步提升代码的健壮性。
内容的提问来源于stack exchange,提问作者tempomax
相关产品推荐
相关产品推荐

