Mongo full text search doesn't find - mongodb

I'm trying to implement full text search in my Mongo database. It's a database of audio tracks metadata. I wan't to search by artistName and title of a track. I have these records in the tracks collection (showing only important fields):
db.tracks.find({},{artistName: 1, title: 1})
{ "_id" : "A10328E00047516670", "artistName" : "Tapani Kansa", "title" : "Tuulia" }
{ "_id" : "A10328E00047516661", "artistName" : "Tapani Kansa", "title" : "Rakkautemme valssi" }
{ "_id" : "A10328E0004751669W", "artistName" : "Tapani Kansa", "title" : "Täysikuu" }
{ "_id" : "A10328E0004751668Y", "artistName" : "Tapani Kansa", "title" : "Muista minua" }
I've created the text index on this collection:
db.tracks.createIndex({artistName: 'text', title: 'text', lyrics: 'text'})
But when I try to search the tracks, no results are returned:
rs-ds047345:PRIMARY> db.tracks.find({$text: {$search: 'Tapani'}}).size()
0
rs-ds047345:PRIMARY> db.tracks.find({$text: {$search: 'Rakkautemme valssi'}}).size()
0
I accidentally noticed, that when I crop some letters from the end of the searched word, I'm starting to get some results... so full text search somehow works, just not in way I would like and expect.
db.tracks.find({$text: {$search: 'Tapa'}}).size()
12
rs-ds047345:PRIMARY> db.tracks.find({$text: {$search: 'Rakkaute'}}).size()
1
Could someone please tell me, how can I search the database using full words, or what I'm doing wrong?
I've tried that on MongoDB versions 3.0.8 and 3.2.1

according to spec -
For case insensitive and diacritic insensitive text searches, the
$text operator matches on the complete stemmed word. So if a document
field contains the word blueberry, a search on the term blue will not
match. However, blueberry or blueberries will match.
what I will suggest is normal index and a regex search
db.tracks.createIndex({"artistName": 1})
db.tracks.createIndex({ "title" : 1})
db.tracks.createIndex({ "lyrics": 1})
db.tracks.find({artistName:"/Tap/[0-10]"}).explain()
the square bracket will force index scan for regex instead of colscan
was testing on 3.0.6 and 3.2.3 with no luck :(

So, the problem was in the documents stored in database. I didn't noticed that they contains a field named language, which changes full text search behaviour, although I tried to disable word stemming by by setting language: 'none' in index and queries.
When I renamed the language field to a different name, the full text search started to work exactly as I expect.

Related

Find doc from field having all specified words

I've problem to find the good document search request do find all documents containing in their 'name' field all the specified values.
I've this document:
{
"_id" : ObjectId("607c1caa4b2964d0185301ff"),
"nb" : 1,
"name" : "mini computer 24GB"
}
When I run the following find request...
db.getCollection('test').find({"$text":{$search:'computer dummy'}})
... the document is returned. An OR is done but I want a AND operation. Should I use a list of $and ?
Many thanks
Ok I found. each word must be in quotes as this:
db.getCollection('test').find({$text:{$search:"\"computer\" \"24GB\""}})
Not really intuitive!

Exact word based search in Solarnet & Mongodb

We have an application where solar-net is integrated with mongodb for searching and full text search is working fine. Now we have to change full text search to exact word based search for example if "DELL" is entered in Search input field, it should only bring up results that are "DELL", and not "DELL Inspiron". Please let us know how to change full text search to exact word based search.Is there any regular expression to do this. Search is based on multiple fields. Please help me.
Thanks
Tarlok
You can use regex as following :
To Search all names starts with "DELL"
db.collectionName.find( { "name" : { $regex : "^DELL.*", $options : "i"} } )
To Search all names contains "DELL" :
db.collectionName.find( { "name" : { $regex : "DELL.*", $options : "i"} } )
here $options : "i" defines ignore case
for more detail visit This.

Search full document in mongodb for a match

Is there a way to match a value with every array and sub document inside the document in mongodb collection and return the document
{
"_id" : "2000001956",
"trimline1" : "abc",
"trimline2" : "xyz",
"subtitle" : "www",
"image" : {
"large" : 0,
"small" : 0,
"tiled" : 0,
"cropped" : false
},
"Kytrr" : {
"count" : 0,
"assigned" : 0
}
}
for eg if in the above document I am searching for xyz or "ab" or "xy" or "z" or "0" this document should be returned.
I actually have to achieve this at the back end using C# driver but a mongo query would also help greatly.
Please advice.
Thanks
You could probably do this using '$where'
db.mycollection({$where:"JSON.stringify(this).indexOf('xyz')!=-1"})
I'm converting the whole record to a big string and then searching to see if your element is in the resulting string. Probably won't work if your xyz is in the fieldnames!
You can make it iterate through the fields to make a big string and then search it though.
This isn't the most elegant way and will involve a full tablescan. It will be faster if you look through the individual fields!
While Malcolm's answer above would work, when your collection gets large or you have high traffic, you'll see this fall over pretty quickly. This is because of 2 things. First, dropping down to javascript is a big deal and second, this will always be a full table scan because $where can't use an index.
MongoDB 2.6 introduced text indexing which is on by default (it was in beta in 2.4). With it, you can have a full text index on all the fields in the document. The documentation gives the following example where a text index is created for every field and names the index "TextIndex".
db.collection.ensureIndex(
{ "$**": "text" },
{ name: "TextIndex" }
)

mongoDB text index on subdocuments

I have a collection that looks something like this
{ "text1" : "text",
"url" : "http:....",
"title" : "the title",
......,
"search_metadata" : { "tags" : [ "tag1", "tag2", "tag3" ],
"title" : "the title",
"topcis": [ "topic1", "topic2"]
}
}
I want to be able to add a text index to search_metadata and all it's subdocuments.
ensureIndex({search_metadata:"text"}) Gives me no results
and:
ensureIndex({"$**":"text"}) will give me irrelevant data
How can I make it happen?
From the text indexes page:
text indexes can include any field whose value is a string or an array
of string elements. To perform queries that access the text index, use
the $text query operator
Your search_metadata field is a series of sub-documents, not a string or an array of strings, so it basically is not in the right format to make use of a text index in MongoDB as it is currently structured.
Now, embedded in search_metadata you have both strings and arrays of strings, so you could use a text index on those, so an index on {search_metadata.tags : "text"} for example fits the criteria and should work just fine.
Hence, it's a choice between restructuring the field to meet the text index criteria, or a matter of indexing the relevant sub-fields. If you take the latter approach you may find that you don't need text indexes on each of the fields and a simpler (and far smaller) index may serve you just as well (using a normal index on tags and then $elemMatch for example).

Mongodb query by regular expression

I use Mongodb to store list of locations over the world, with more than 2M records. Each record is an object like this:
{ "_id" : ObjectId("4e5b339feee76320ab26f930"), "city" : "New York", "longitude" : -87.2008333, "latitude" : 30.8383333, "country_code" : "US", "country_name" : "United States" }
I want to perform the search to get out all "CITIES" contain "New York", it took me about 10 seconds to have the result (it is unacceptable in my web system). I have indexed the "city" using ensureIndex() function, but the query is still slow.
Here is my query:
db.locations.find({"city": { "$regex": "(New York)", "$options": 'i' }})
I guess the problem is the "regular expression". Can you suggest me a solution for this to get the query result within 2-3 seconds (I have more than 4M records in MySQL, the similar query took me only 1-2 seconds - with indexes).
Thanks and regards.
You can't search with contain operation in mongodb without using regexp or javascript (they are slow, because of work without index).
I can suggest to store additional city in lower case and search by full match. If you want 'contains' and fast speed you should use some another full text search engines like solr or lucene.
I recommends use multi keys.
example:
{ title : "this is fun" ,
_keywords : [ "this" , "is" , "fun" ]
}
then you can use
db.articles.findOne( { _keywords: "this" } )
this will be more faster
Mongo doesn't use index for regexp when it search with case insensitive. I suggest you to store your field with uppercase or lowercase and use same for search.
Instead of search containing if you search start with like below
db.locations.find({"city": { "$regex": /^New York/}})
your query will return fast .
for more info RegularExpressions