I think you will need to use some kind of regex here. Instead of joining the arguments by a space, you could join 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'. As a regex pattern, /ani.*call/ matches any string that contains both ani and call (in this order).
const args = ['ani', 'call']
const regex = new RegExp(args.join('.*'), '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'))
If you don't want to match words without any additional characters between them, you can join the words with .+. Using the + sign requires at least one extra character between the two strings; this way it won't match anicall:
const args = ['ani', 'call']
const regex = new RegExp(args.join('.+'), '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'))
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 to make it more readable:
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);
