Mongoose not returning Regex substrings - node.js

Reference.find(
{$and: [
{'url': url},
{"text" : {$regex : text, '$options' : 'i'}}
]})
Whenever I test out text with 'Hello World', I get back documents that have that text exactly. However, if I were to do 'Hello Worl', I get nothing back, even with the same url. I've tried numerous implementations of ReGex, and so far none have worked. I'm using Mongo 3.2.11 if that matters.

Try with the following string '.*content.*' or regex format /.*content.*/, which are the widely supported regex formats.
Also, see Checking if a field contains a string

Related

Not able to search a query using find methon properly in mongoDB

Here I am trying to find all those documents having searched string in cui_str of either population_mesh or intervention_mesh or outcome_mesh
I am using $or property to find from three different fields. I am using below query from nodejs to fetch from mongodb.
exports.searchQuery= (req,res) => {
const picoSearch = req.query.text
Pico_tests.find({$or : [{"population_mesh.cui_str" : {$regex: `${picoSearch}`,$options: '$i'}},{"intervention_mesh.cui_str" : {$regex: `${picoSearch}`,$options: '$i'}},
{"outcomes_mesh.cui_str" : {$regex: `${picoSearch}`,$options: '$i'}}]}).then((data)=>{
res.send(data)
})
// Here i am searching in three different fields but is fetching all the documents irrespective of any string searched.
}
But in the result I am getting all the documents rather than specific documents containing that string. I have check a lot of time in database that given string(i.e Patient) searched but I got all the documents rather than specific one.
It was very silly mistake of spell which make all docs get fetched.

MongoDB: multi-lingual (accent insensitive), case insensitive search, with partial words?

For the application we are developing we need to allow our searches to support accents, be case insensitive and search for partial words. For example, given the product name "La Niña" in our collection, the following searches should be expected to return the entry:
La Niña
niña
nina
nin
La nin
Currently I have tried two approaches, each with their appear apparent limitations, based on testing and some research:
Regex
supports case insensitive and partial searches
does not support accents such that, niña != nina
Text Search
support case insensitive, accents and partial phrases
does not support partial words
Example regex search, as we have used:
function escapeRegExp(text) {
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
const escapedStr = this.escapeRegExp(searchTerm);
await Product.find({ name: new RegExp(`${escapedStr}`, 'i') });
Example text search, as we have used:
// On the schema
storeSchema.index({ name: 'text' });
// Searching:
await Product.find($text: { $search: searchTerm })
.collation({locale: 'en', strength: 1});
BTW We have set the schemas in question to use collation strength level 1.
Some approaches I am considering, if MongoDB doesn't provide a solution:
shadow name field (not sure the right term?), with the accents removed
a separate full text search engine
Can anyone help here?
Note, we are leveraging mongoose 5.9.5, with node 12.16.2 and mongodb 4.3.8 running in mongo cloud.
I believe the Text Search is what you need. There are two other features of Text Search that fulfills the requirement of a partial word match you described in the question.
Stop Words: Given a language option, MongoDB Text Search is capable of identifying words that shouldn't influence search results. The frequency of usage of these words is such that they appear in almost every sentence, for example, in English, words like "the", "a", "of", are all stop words. These words are stripped off the search phrase before the actual search takes place.
Word Stemming: Given a language option, MongoDB Text Search is capable of identifying the root version of a word, for example, in English, the stem version of "identifying" would be "identify" so they both would match in a text search".
I was able to figure with Google Translate that the "La Niña" example you gave is in Spanish.
If I insert the following into a sample product collection:
db.products.insertMany([
{ "term" : "La Niña" },
{ "term" : "niña" },
{ "term" : "nina" },
{ "term" : "nin" },
{ "term" : "La nin" },
])
By specifying a language option of "spanish" on my Test Search query:
db.products.find({ $text: { $search: "La Niña", $language: "spanish" } })
MongoDB would effectively match that with all the products that were previously inserted. You can get a list of the supported language options for MongoDB here.
I'm not 100% sure of how the accent matching works though.

Find records in mongo db with regular expression search on certain field gives incorrect answer

I have query,
db.getCollection(collection).find({$and: [
{street: {$regex: new RegExp('7/838(B) Seaport - Airport Road', 'i')}}
]})
the db contain the exact data, but returns nothing. How to write a correct query for get the result ?
Try this, You don't need $and for that.
db.getCollection('collection').find({"street" : new RegExp("7/838(B) Seaport - Airport Road","i")})

Query subdocuments without knowing the keys

I have a collection like this:
{
"_id" : ObjectId("5a7c49b02d2bbb28a4b2e6a2"),
"phone" : "Pinheiro",
"email" : "Pinheiro",
"variableParameters" : {
"loremIpsum" : "Do you see a little Asian child with a blank expression on his face sitting outside on a mechanical helicopter that shakes when you put quarters in it?",
"uf" : "Rio de Janeiro",
"city" : "Rio de Janeiro",
"end" : "RUA JARDIM BOTÂNICO 1060",
"tel" : "5521999999999",
"eml" : "teste#gmail.com",
"nome" : "Usuario de Teste"
}
}
And i want to query the "variableParameters" object, but like the name said, this properties are variable. So in some cases it will have "uf", but in other cases won't.
I'm actually doing a query that only matches the constant field from a mongoose schema:
{ 'phone': { $regex: filter, $options: 'i' } }
Is there any way that I can query "variableParameters" without knowing his child properties?
If you are unsure about the keys(since they are variable), then try using $text search
To use text search we need to index the variableParameters.
Case sensitive text search can also be performed but it comes with the impact on performance.
Please read https://docs.mongodb.com/manual/reference/operator/query/text/ for more information on text search
[SOLVED]
Thanks #Clement Amarnath for the help.
The solution is something like this:
_Events.find({ $text: { $search: 'searchText' } }, (err, events) => {
if (err) return Exceptions.HandleApiException(err, res);
res.send(events);
});
The $text parameter can have this properties:
{
$text: {
$search: <string>,
$language: <string>,
$caseSensitive: <boolean>,
$diacriticSensitive: <boolean>
}
}
$search A string of terms that MongoDB parses and uses to query the text index. MongoDB performs a logical OR search of the terms unless specified as a phrase. See Behavior for more information on the field.
$language Optional. The language that determines the list of stop words for the search and the rules for the stemmer and tokenizer. If not specified, the search uses the default language of the index. For supported languages, see Text Search Languages.
If you specify a language value of "none", then the text search uses simple tokenization with no list of stop words and no stemming.
$caseSensitive Optional. A boolean flag to enable or disable case sensitive search. Defaults to false; i.e. the search defers to the case insensitivity of the text index.
$diacriticSensitive Optional. A boolean flag to enable or disable diacritic sensitive search against version 3 text indexes. Defaults to false; i.e. the search defers to the diacritic insensitivity of the text index.
For more information, see MongoDB Documentation.
You can use $where to build your own matching function.
An example for a full-text match would be:
db.col.find({$where: function(){
return Object.values(this.variableParameters).includes("Rio de Janeiro")
}})

Unaccent in Sequelize

I'm currently working in a project that uses ExpressJS, PostgreSQL and Sequelize as the ORM. I developed a search function that makes a query that searches items by name:
models.foo.findAll({
where: {
$or: [
{name: {$ilike: keywords}},
{searchMatches: {$contains: [keywords]}}
]
},
order: [['name', 'ASC']]
})
This works fine, but if the name contains an special character (like á, é, í, ó or ú) this query won't find it.
Is there a way to make the query search names with speacial characters in a meaningful sense? Like if I search the name "potato" the results "The potato", "Da potátos" and "We are the pótatóes" will come out, but not "We eat pátatos" (since á != o)
This can now be done without a completely RAW query, but using Sequelize's in built functions:
models.foo.findAll({
where: Sequelize.where(
Sequelize.fn('unaccent', Sequelize.col('name')), {
[Op.iLike]:`%${keywords}%`
}),
order: [['name', 'ASC']]
})
Then ordering, associations etc. all work still as normal :).
I finally found a valid solution. First I created the unaccent extension:
create extension unaccent;
Then I just used a raw query (I couldn't figure out how to build the query using Sequelize's way) like this:
models.sequelize.query(
`SELECT
*
FROM
"Foos"
WHERE
unaccent("name") ilike unaccent('${keywords}')
OR "searchMatches" #> ARRAY[unaccent('${keywords}')]::VARCHAR(255)[]
ORDER BY
"name" ASC`, {model: models.Foo})
And it works!
A dictionary might be what you are looking for. Can basically be used to map synonyms and exclude common elements from indexes (e.g. "a" and "the" from English text), amongst other things.
https://www.postgresql.org/docs/current/static/textsearch-dictionaries.html
In my case I solved this question using the Sequelize.literal and COLLATE that way:
where: Sequelize.literal(`name COLLATE Latin1_general_CI_AI like '%${keywords}%' COLLATE Latin1_general_CI_AI`)
That way, removing the accents on both sides.

Resources