I have an index in MongoDB which covers name and email.
This works, and I can query it with:
const c = await Contact.
find({ $text: { $search: search } }, { score: { $meta: "textScore" } })
.sort({ score: { $meta: "textScore" } })
.skip(skip)
.limit(20);
But, the results are somewhat odd, yet logical.
e.g.
if I search for "Roger Johan"
It will start listing both people called Roger and Johan, which is logical.
but, it would have been less odd if it ranked "Roger Johansson" highest as that is a match on both Roger and Johan%
Is there any way to tune this?
I know I can regex match on partial, but that instead fails on things like:
data: Roger T. Johansson
query: Roger Johansson
Is there any fancy trick to combine parts of these two options?
If you apply search by phrase it will be able to find Roger Johan, but it won't work if you will try to search for Rog or Johan.
To make it work with partial matches on the first word we created additional field with prefixes for the word, i.g. ["Rog", "Roge"] and included this field into text index.
Having that implemented search will be able to find searches for Rog as well as Roger Johan.
If you need to search last name Johan you can also include another property with prefixes ["Joh", "Joha", "Johan", "Johans", "Johanss", "Johansso"] and give it lower (or higher, depending on how you want results to appear) rank. Or you can include all prefixes to the same array property if the rank should be same.
Just to be clear, you do need to use phrase search, i.e.: "\"Roger Johan"\".
I haven't tried it myself, but maybe you need to do the search as a phrase: https://docs.mongodb.com/manual/reference/operator/query/text/#phrases
If not I think it will split your search term and then search.
Related
I'm writing a UI that presents the results of a MongoDB full text search query, visually highlighting the matched search terms in each result; this works well enough for full word or phrase matches, but not for partial/fuzzy matches.
For example, if I search for "delete" a will get a search result that contains "deletion", which does not contain the full word "delete" and therefore won't be highlighted if I merely highlight the full search term matches. I do want the partial matches, though.
Is there any way to project the set of matched words/substrings when I execute the query?
I've so far been unable to find anything in the docs that hints at this being possible, but I thought it worth asking around. Any help would be greatly appreciated.
You can use the Mongo DB Atlas feature where you can search your text based on different Analyzers that MongoDB provides. And you can then do a search like this: Without the fuzzy object, it would do a full-text-match search.
$search:{
{
index: 'analyzer_name_created_from_atlas_search',
text: {
query: 'Text to do a full match or fuzzy match with',
path: 'sentence',
fuzzy:{
maxEdits: 2 #max 2 is allowed
}
}
}
}
How to find partial search?
Now Im trying to find
db.content.find({$text: {$search: "Customer london"}})
It finds all records matching customer, and all records matching london.
If I am searching for a part of a word for example lond or custom
db.content.find({$text: {$search: "lond"}})
It returns an empty result. How can I modify the query to get the same result like when I am searching for london?
You can use regex to get around with it (https://docs.mongodb.com/manual/reference/operator/query/regex/). However, it will work for following :
if you have word Cooking, following queries may give you result
cooking(exact matching)
coo(part of the word)
cooked(The word containing the english root of the document word, where cook is the root word from which cooking or cooked are derived)
If you would like to go one step further and get a result document containing cooking when you type vooking (missplled V instead of C), go for elasticsearch.
Elasticsearch is easy to setup, has extremely powerful edge-ngram analyzer which converts each words into smaller weightage words. Hence when you misspell, you will still get a document based on score elasticsearch gives to that document.
You can read about it here : https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-edgengram-tokenizer.html
it will always return the empty array for partial words like when you are searching for lond to get this type of text london..
Because it take full words and search same as that they are ..
Not achive same results like :-
LO LON LOND LONDO LONDON
Here you may get help from ELASTIC-SEARCH . It is quite good for full text search when implement with mongoDB.
Refrence : ElasticSearch
Thanks
The find all is to an Array
clientDB.collection('details').find({}).toArray().then((docs) =>
I now used the str.StartWith in a for loop to pick out my record.
if (docs[i].name.startsWith('U', 0)) {
return console.log(docs[i].name);
} else {
console.log('Record not found!!!')
};
This may not be efficient, but it works for now
Is it possible to query documents where a specific field is contained in a given string?
for example if I have these documents:
{a: 'test blabla'},
{a: 'test not'}
I would like to find all documents that field a is fully included in the string "test blabla test", so only the first document would be returned.
I know I can do it with aggregation using $indexOfCP and it is also possible with $where and mapReduce. I was wandering if it's possible to do it in find query using the standard MongoDB operators (e.g., $gt, $in).
thanks.
I can think of 2 ways you could do this:
Option 1
Using $where:
db.someCol.find( { $where: function() { return "test blabla test".indexOf(this.a) > -1; } }
Explained: Find all documents whose value of field "a" is found WITHIN some given string.
This approach is universal, as you can run any code you like, but less recommended from a performance perspective. For instance, it cannot take advantage of indexes. Read full $where considerations here: https://docs.mongodb.com/manual/reference/operator/query/where/#considerations
Option 2
Using regex matching trickery, ONLY under certain circumstances; below is an example that only works with matching that the field value is found as a starting substring of the given string:
db.someCol.find( { a : /^(t(e(s(t( (b(l(a(b(l(a( (t(e(s(t)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?$/ } )
Explained: Break up the components of your "should-be-contained-within" string and match against all sub-possibilities of that with regex.
For your case, this option is pretty much insane, but it's worth noting as there may be specific cases (such as limited namespace matching), where you would not have to break up each letter, but some very finite set of predetermined parts. And in that case, this option could still make use of indexes, and not suffer the $where performance pentalties (as long as the complexity of the regex doesn't outweigh that benefit :)
You can use regex to search .
db.company.findOne({"companyname" : {$regex : ".*hello.*"}});
If you are using Mongo v3.6+, you can use $expr.
As you mentioned $indexOfCP can be used to get index, here it will be
{
"$expr": {
{$ne : [{$indexOfCP: ["test blabla test", "$a"]}, -1]}
}
}
The field name should be prefixed with a dollar sign ($), as $expr allows filters from aggregation pipeline.
I'm currently having some issues with the full text search functionality in MongoDB with or condition. Specifically when trying to match exact phrases with or condition.
Exact Phrase and or condition Not working properly in mongodb full text search
{
$text: { $search: "cake \"coffee shop\"" }
}
i want result which find all documents containing “cake” or “coffee shop”:
Have a look here.
If the search string includes phrases, the search performs an AND with any other terms in the search string; e.g. search for "\"twinkle twinkle\" little star" searches for "twinkle twinkle" and ("little" or "star").
What is the best strategy for selecting mongodb entries in which a string value contains a set of words or phrases? I'm thinking of something equivalent to mysql's LIKE function, e.g.
WHERE (TEXT LIKE "% apple %") or (TEXT LIKE "% banana %")
I've seen options that involve tokenizing the string, but this would involve building unigrams for all the text, which would be huge no?
Mongo now supports text search since 2.4.
My experience has been pretty positive
http://docs.mongodb.org/manual/applications/text-search/
You start the server with setParameter text search enabled
Then enable the index on the collection
Then search with runCommand
MongoDB has no full text search capability right now, but it's easy to use external search engines like SOLR.
I strongly discourage you trying to rebuild text search with Regex or word stemming etc. yourself. You should rather focus on your app own features :)
I am using this combination: Mongoid, Sunspot and Mongoid-Sunspot. It works very well in production, and development setup is easy.
You can use the regular expression support in MongoDB queries. More details available # the following link
http://docs.mongodb.org/manual/reference/operator/regex/
Here are two examples should the above link move again in the future:
db.collection.find( { field: /acme.*corp/i } );
db.collection.find( { field: { $regex: 'acme.*corp', $options: 'i' } } );
Somehow MongoDB built-in text search failed to meet my requirements on an existing database which used a compound index. I am now using mongoose-search-plugin and it has been working superbly well. It uses natural stemming, and distance algorithms to return a relevance score.
User.search('Malaysia Car Food',{username:1},{}, function(err, u){
console.log('Search Results: '+JSON.stringify(u));
});