Finding results with mongodb

I have a db full of skills and I’m trying to make an info cmd where if you type the skill name you will get some info on it. Some skills are 2-3 arguments. For example "Animal Call". I want to be able to find my skill in mongodb by typing both !info animal call and for example something short like !info ani call

The problem about this is that if i try to find it with !info ani call it wont show up as a result.

Here’s my code:

let skill = args.slice(0).join(" ");

const skillDB = await Skill.find({})

for (let i = 0; i < skillDB.length; i++) {
 if (skillDB[i].skillName.toLowerCase().includes(`${skill.toLowerCase()}`)) {
  const embed = new MessageEmbed()
  .setDescription(`\`${skillDB[i].skillIcon}\` ${skillDB[i].skillName}`)
  .setImage(skillDB[i].skillImg)
  return message.channel.send(embed)
 }
}

18 thoughts on “Finding results with mongodb”

  1. I think you will need to use some kind of regex here. Instead of joining the arguments by a space, you could joined them by .* and use that as a regex.

    .* matches any characters, so when you join ['ani', 'call'], it will become a string like 'ani.*call'. Any string that contains ani and call is a match.

    const regex = new RegExp('ani.*call', 'i')
    
    console.log('Words matching /ani.*call/i:')
    console.log('animal', regex.test('animal'))
    console.log('animal call', regex.test('animal call'))
    console.log('anime caller', regex.test('anime caller'))
    console.log('anicall', regex.test('anicall'))
    console.log('animal cruelty', regex.test('animal cruelty'))
    console.log('anemia caribou', regex.test('anemia caribou'))

    If you don’t want to match words without any additional characters between them, you can join the words with .+. This way it won’t match anicall:

    const regex = new RegExp('ani.+call', 'i')
    
    console.log('Words matching /ani.+call/i:')
    console.log('animal', regex.test('animal'))
    console.log('animal call', regex.test('animal call'))
    console.log('anime caller', regex.test('anime caller'))
    console.log('anicall', regex.test('anicall'))
    console.log('animal cruelty', regex.test('animal cruelty'))
    console.log('anemia caribou', regex.test('anemia caribou'))

    You could also use [a-z\s]+ to only accept characters in the range a-z and whitespace:

    const args = ['ani', 'call']
    const regex = new RegExp(args.join('[a-z\\s]+'), 'i')
    
    console.log(`Words matching ${regex}:`)
    console.log('animal', regex.test('animal'))
    console.log('animal call', regex.test('animal call'))
    console.log('anime caller', regex.test('anime caller'))
    console.log('anicall', regex.test('anicall'))
    console.log('animal cruelty', regex.test('animal cruelty'))
    console.log('anemia caribou', regex.test('anemia caribou'))

    With your current code, you could use the .test() method instead of .includes(). It searches for a match between a regex and a specified string.

    You could also use a for ... of loop instead of the for loop:

    const regex = new RegExp(args.join('[a-z\\s]+'), 'i');
    const skills = await Skill.find({});
    const embed = new MessageEmbed();
    
    for (let skill of skills) {
      if (regex.test(skill.skillName)) {
        embed
          .setDescription(`\`${skill.skillIcon}\` ${skill.skillName}`)
          .setImage(skill.skillImg);
    
        return message.channel.send(embed);
      }
    }
    

    I’m not sure why you’re fetching every skill from the database though. You could also use find() or findOne() with the regex above to only fetch the data you need:

    const regex = new RegExp(args.join('[a-z\\s]+'), 'i');
    // findOne returns a single object or null if not found
    const skill = await Skill.findOne({
      skillName: { $regex: regex },
    });
    
    if (!skill) {
      return message.channel.send(
        `Oops, I couldn't find any skill in the database for \`${args.join(' ')}\``,
      );
    }
    
    const embed = new MessageEmbed()
      .setDescription(`\`${skill.skillIcon}\` ${skill.skillName}`)
      .setImage(skill.skillImg);
    
    return message.channel.send(embed);
    

    enter image description here

    Reply

Leave a Comment