Introduction
I am building a search feature using mongodb with mongoose ODM. The codebase is already having an search feature using javascript. The code
terms.every((term) => {
const cleanedTerm = term.trim();
return (
usernameLower.includes(cleanedTerm) ||
nameLower.includes(cleanedTerm) ||
userTagsString.includes(cleanedTerm) ||
userLocationString.includes(cleanedTerm)
);
});
First all the users are fetched and then getting filtered. The documents which consists of every elements of the array in any of its fields are getting returned.
My Approach
async function searchUsers(termsArray) {
const query = { $in: termsArray }
return await Profile.find({
$or: [
{ username: query },
{ name: query },
{ "location.name": query },
{ tags: { $all: termsArray } },
],
});
}
Problem and Example
Basically this query is returning the documents which is matching any of the elements of the terms or tags.
Example – Suppose a profile is having tags [JS,TS,OSS] and search terms are [JS,TS,OSS,JAVA] then also the profile is getting returned which is not expected as JAVA is not present.
2
Answers
first thing you have use $or so any of condition satisfied it will return records,
any username or name matches in record and that record is having this [JS,TS,OSS,JAVA] it is valid,
you have to make condition using $AND or otherwise
you can try $ size along with you query
So if you only want profiles to be returned if ALL tags listed in the
termsArray
are present in the profile, and if ANY of thetermsArray
terms are present in either theusername
orname
orlocation.name
of the same profile then you need to combine$and
with$or
. Refactor your aggregation like so:The
$and
states that both conditions need to be true. One of those conditions is an$or
so any of the 3 conditions in the$or
can be true but the{ tags: { $all: termsArray } }
must also be true.