如何检查对象是否包含至少一个其值包含JavaScript子字符串的键?

时间:2018-03-02 21:56:01

标签: javascript string object substring filtering

我想编写一个函数来检查一个对象是否至少有一个包含子字符串的值。像这样的东西(伪代码):

const userMatchesText = (text, user) => user.includes(text);

我的对象的完整结构(

因此,对于以下用户:

const user = {
    id: '123abc',
    info: {
        age: 12,
        bio: 'This is my bio' 
    },
    social: {
        chatName: 'Chris',
        friends: ['friend1', 'other friend'],
        blocks: ['Creep']
    }
    //Etc. The objects I'm working with contain nested objects and arrays, etc.
}

userMatches('bi', user)应返回true,因为子字符串' bi&#39}在bio中找到:'这是我的bi o'。 userMatches(' 324d,user)同样应返回false。但是,usermatches('blocks', user)应返回false,因为子字符串只能在其中一个键中找到,而不是其中一个值。

我工作的对象看起来像这样(Mongoose Schema):

{
    account  : {
        dateOfCreation : Number
    },
    social   : {
        chatName         : String,
        friends          : [ { type: String } ],
        blocks           : [ { type: String } ],
        sentRequests     : [ { type: String } ],
        recievedRequests : [ { type: String } ],
        threads          : [ { type: String } ]
    },
    info     : {
        age            : Number,
        bio            : String,
        displayName    : String,
        profilePicture : String,
        subjects       : {
            tutor   : [
                {
                    subject : String,
                    level   : String
                }
            ],
            student : [
                {
                    subject : String,
                    level   : String
                }
            ]
        }
    },
    facebook : {
        id         : String,
        firstName  : String,
        middleName : String,
        fullName   : String,
        lastName   : String
    }
}

到目前为止,我发现这样做的最好方法是解析所有关键字的关键字,然后使用mapincludes,就像下面的函数一样。< / p>

const doesUserMatchText = (user, text) => {
    const { social: { chatName }, info: { displayName }, facebook: { firstName, middleName, lastName } } = user;
    const possibleMatches = [ chatName, displayName, firstName, middleName, lastName ];
    let match = false;
    possibleMatches.map(possibleMatch => {
        if (possibleMatch.includes(text)) {
            return (match = true);
        }
    });
};
然而,这是非常烦人的(也可能非常低效),因为与我合作的对象非常庞大。如果我可以调用userMatchesText(text, user)并获得布尔值,那真的很好。非常感谢提前!

另外,请注意我并没有解析所有Strings键。此功能的目的是根据搜索查询过滤用户,我认为让用户通过他们的bio,id等为其他用户提供服务可能没什么意义,而只是通过他们的各种&#39;名称&#39;

3 个答案:

答案 0 :(得分:4)

您可以使用递归函数来遍历整个对象。只需确保该对象没有任何循环引用...

const user = {
    id: '123abc',
    info: {
        age: 12,
        bio: 'This is my bio' 
    },
    social: {
        chatName: 'Chris',
        friends: ['friend1', 'other friend'],
        blocks: ['Creep']
    }
    //Etc. The objects I'm working with contain nested objects and arrays, etc.
};

function userMatchesText(text, user) {
    if (typeof user === "string") return user.includes(text);
    return Object.values(user).some(val => userMatchesText(text, val));
}

console.log(userMatchesText("bi", user));
console.log(userMatchesText("other fri", user));
console.log(userMatchesText("zzz", user));

答案 1 :(得分:2)

纯JavaScript。这会迭代对象键,一旦找到一个匹配项,它就会返回true。

最糟糕的情况是当结果为false时,它会遍历所有键和子键。

&#13;
&#13;
(function() {
  var user = {
    id: '123abc',
    info: {
      age: 12,
      bio: 'This is my bio'
    },
    social: {
      chatName: 'Chris',
      friends: ['friend1', 'other friend'],
      blocks: ['Creep']
    }
    //Etc. The objects I'm working with contain nested objects and arrays, etc.
  };

  console.log('userMatches(\'bi\', user): ' + userMatches('bio', user));
  console.log('userMatches(\'324d\', user): ' + userMatches('324d', user));
  console.log('usermatches(\'blocks\', user) ' + userMatches('blocks', user));

  function userMatches(str, obj) {
    var queue = [];
    for (var k in obj) {
      if (obj.hasOwnProperty(k)) {
        if (typeof obj[k] === 'string') {
          if (obj[k].indexOf(str) !== -1) {
            return true;
          }
        } else {
          queue.push(obj[k]);
        }
      }
    }
    if (queue.length) {
      for (var i = 0; i < queue.length; i++) {
        if (userMatches(str, queue[i])) {
          return true;
        }
      }
    }
    return false;
  }
}());
&#13;
&#13;
&#13;

答案 2 :(得分:1)

这应该可以解决问题:

(见代码下面的解释)

const findInObject = (predicate, object) => {
  if (typeof object !== 'object') {
    throw new TypeError('Expected object but got ' + typeof object)
  }
  
  for (let key in object) {
    const value = object[key]
    switch (typeof value) {
      case 'object':
        if (findInObject(predicate, value))
          return true
      default:
        if (predicate(value))
          return true
    }
  }
  return false
}

const userContainsText = (text, user) => 
  findInObject(
    val => {
      if (typeof val !== 'string')
        return false
        
      return val.includes(text)
    },
    user
  )
  
const user = {
    id: '123abc',
    info: {
        age: 12,
        bio: 'This is my bio' 
    },
    social: {
        chatName: 'Chris',
        friends: ['friend1', 'other friend'],
        blocks: ['Creep']
    }
}

console.log(userContainsText('Chris', user))

findInObject功能可以解决繁重的问题。您提供谓词(这是一个函数,根据输入“通过”返回truefalse)和一个要搜索的对象。它在对象中的每个键上运行谓词,如果提供的对象包含对象,则以递归方式运行谓词。它应该停止搜索它是否匹配。否则,它会传播整个物体。

userContainsText函数使用findInObject。它提供了一个谓词,用于检查所获得的任何字符串的内容。 (任何其他类型都未通过测试)。此函数接受要查找的文本和要搜索的用户对象(虽然从技术上讲,这可以由任何对象,而不是“用户”对象)。