MongoDB text search, exact phrase and logical operators [duplicate] - mongodb

Here is the model 'Class' model for which I have created the "text" index for 'keywords','lifeArea',''type'.
Structure of the model:
{
"_id" : ObjectId("558cf6e3387419850d892712"),
"keywords" : "rama,seetha",
"lifeArea" : [
"Emotional Wellness"
],
"type" : "Pre Recorded Class",
"description" : "ram description",
"synopsis" : "ram syn",
"name" : "ram demo",
"__v" : 0
}
db.Class.getIndexes()
// displaying index
{
"v" : 1,
"key" : {
"_fts" : "text",
"_ftsx" : 1
},
"name" : "classIndex",
"ns" : "innrme.classes",
"weights" : {
"keywords" : 1,
"lifeArea" : 1,
"type" : 1
},
"default_language" : "english",
"language_override" : "language",
"textIndexVersion" : 2
}
I want to do a text search on the fields mentioned above. I tried the following query.
db.classes.find({$or:[{keywords: { $text: { $search: "rama abc" } } }, {type: {$text: { $search: "class" }}}],score: {$meta: 'textScore'}});
But it did not work and I got the follwing error
Error: error: {
"$err" : "Can't canonicalize query: BadValue unknown operator: $text",
"code" : 17287
}
Please help me to get the correct query.
Please correct/educate me if I am wrong in asking the question or in explaining the problem

That actual error suggests your mongodb is a version less than 2.6 ( so no text search in that way ). But you cannot do that anyway for two reasons.
An $or expression can only have one special index expression, being either "text" or "geospatial" in the arguments.
You are expecting text searches on "two" different fields and you can only have one text index per collection. However that single index can be spread over several fields in the document. But you cannot ask different search terms for different fields.
Documentation quote:
You cannot combine the $text expression, which requires a special text index, with a query operator that requires a different type of special index. For example you cannot combine $text expression with the $near operator.
And it should also say "You cannot use $or with a $text expression or the $near operator where either are used in more than one condition." But that little piece of information is missing, but you still cannot do it.
Your syntax is generally not correct, but even with the correct syntax in a supported version of MongoDB you would get an error trying to use $or like this:
Error: error: {
"$err" : "Can't canonicalize query: BadValue Too many text expressions",
"code" : 17287
}
So to resolve this you need:
To have a MongoDB server version of 2.6 or greater that supports the $text syntax ( or live with command forms )
To live with indexing over multiple fields and using a single index.
To execute "separate queries" in place of your "or" conditions and "combine" the results in your client API interface.
That is the only way you get "or" conditions like this with MongoDB text search.

First of all I don't think you can use $text in that manner, you need first to create a text index on the collection then you can use it but without specifying any field because it works on indexes not fields.
Please check here: http://docs.mongodb.org/manual/administration/indexes-text/

Related

PyMongo delete document by type

Cashbook Collection
{ "_id" : ObjectId("1"), "DR" : "Bank", "CR" : "Roger", "Amount" : "100.00" }
{ "_id" : ObjectId("2"), "DR" : "Bank", "CR" : "Amy", "Amount" : 999.99 }
...
CB = conn['Cashbook']
def CB_del_mult(search,value):
query = {search:value}
CB.delete.many(query)
CB.delete_many('Amount'," { $type : 'string' }")
According to the MongoDO Docs, I can query by type.
I am attempting to remove all documents from Cashbook collection depending on whether 'Amount' is a string value. In this example, the 1st entry will be completely removed as Amount is “100.00” (not 100.00)
The above code raises no errors, however is not deleting the string values.
Something like CB.delete_many('Amount',{$type : 'string'} ) raises an invalid syntax error
Many thanks
JS and Python syntaxes are different and you need to use the correct one for the language you are working with.
Use pymongo documentation to find out the proper method signatures, options etc. to use with pymongo. E.g. https://pymongo.readthedocs.io/en/stable/api/pymongo/collection.html for delete_many.
CB.delete_many({'Amount': {'$type': 'string'}})

reserved words (Where, from , and) in full text search query in mongo db

I am using mongodb, I am stucked on a issue :
Data is :
{
"_id" : ObjectId("5a956e0b78d363d37f6a2ec4"),
"fieldType" : "Enter Source",
"value" : "Delhi",
"catgeory" : "Generic",
"synonym" : [
"origin name or code",
"from",
"enter source",
"from where",
"fro wher"
]
}
When I use this query
db.getCollection("Rules_DefaultValue").find(
{
"synonym" : "from where"
});
I got correct result as expected
But when I use this query
db.getCollection("Rules_DefaultValue").find(
{
"$text" : {
"$search" : "where"
}
});
I didn't got any result , So I changed it again
db.getCollection("Rules_DefaultValue").find(
{
"$text" : {
"$search" : "wher"
}
});
and this time it worked.
So I came to a conclusion that "where" is reserve keyword and I can't use it as it is. So I tried with escape char :
"$search" : "\"where\""
but again I did'nt got the result.
same thing is happening with
and , from , *
Please help me on this , How can I make query with these words.
Words like where and from are considered as stopwords in MongoDB. It means that when you create a text index those words are wiped out from the index since they appear very frequently in English while the point of FTS is to index some words that allow you to easily find the document you're looking for. To fix that you can create your text index specifying language to none, try:
db.getCollection("Rules_DefaultValue").createIndex(
{ synonym : "text" },
{ default_language: "none" }
)
Then your query should return the document mentioned in your post.

I have big database on mongodb and can't find and use my info

This my code:
db.test.find() {
"_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
"title" : "Sir",
"name" : {
"_id" : ObjectId("4d3ed089fb60ab534684b7ff"),
"first_name" : "Farid"
},
"addresses" : [
{
"city" : "Baku",
"country" : "Azerbaijan"
},{
"city" : "Susha",
"country" : "Azerbaijan"
},{
"city" : "Istanbul",
"country" : "Turkey"
}
]
}
I want get output only all city. Or I want get output only all country. How can i do it?
I'm not 100% about your code example, because if your 'find' by ID there's no need to search by anything else... but I wonder whether the following can help:
db.test.insert({name:'farid', addresses:[
{"city":"Baku", "country":"Azerbaijan"},
{"city":"Susha", "country":"Azerbaijan"},
{"city" : "Istanbul","country" : "Turkey"}
]});
db.test.insert({name:'elena', addresses:[
{"city" : "Ankara","country" : "Turkey"},
{"city":"Baku", "country":"Azerbaijan"}
]});
Then the following will show all countries:
db.test.aggregate(
{$unwind: "$addresses"},
{$group: {_id:"$country", countries:{$addToSet:"$addresses.country"}}}
);
result will be
{ "result" : [
{ "_id" : null,
"countries" : [ "Turkey", "Azerbaijan"]
}
],
"ok" : 1
}
Maybe there are other ways, but that's one I know.
With 'cities' you might want to take more care (because I know cities with the same name in different countries...).
Based on your question, there may be two underlying issues here:
First, it looks like you are trying to query a Collection called "test". Often times, "test" is the name of an actual database you are using. My concern, then, is that you are trying to query the database "test" to find any collections that have the key "city" or "country" on any of the internal documents. If this is the case, what you actually need to do is identify all of the collections in your database, and search them individually to see if any of these collections contain documents that include the keys you are looking for.
(For more information on how the db.collection.find() method works, check the MongoDB documentation here: http://docs.mongodb.org/manual/reference/method/db.collection.find/#db.collection.find)
Second, if this is actually what you are trying to do, all you need to for each collection is define a query that only returns the key of the document you are looking for. If you get more than 0 results from the query, you know documents have the "city" key. If they don't return results, you can ignore these collections. One caveat here is if data about "city" is in embedded documents within a collection. If this is the case, you may actually need to have some idea of which embedded documents may contain the key you are looking for.

MongoDB difference between $orderby and Sort

I want to fetch the latest document, which obviously is a single document, thus findOne should work fine. But findOne here returns the first document inserted. So I have two options now either use $orderBy with findOne or use .sort() function with .limit() in find()
Using $orderBy it would look something like:
db.collection.findOne({$query:{},$orderby:{_id:-1}})
And using sort:
db.collection.find().sort({_id:-1}).limit(1).pretty()
Both work fine, I just wanted to know which query should I prefer here? In terms of performance, or does both of them work the same way internally and there is no such difference between the two.
As of Mongo 3.2, $orderby is deprecated.
The docs explicitly say:
The $orderby operator is deprecated. Use cursor.sort() instead.
Unfortunately, findOne() doesn't support the sort() method, so you'll need to switch to find():
db.collection.find({}).sort({'key': -1}).limit(1)
This will return a cursor, so you'll then need to pull the first result from the cursor.
They are the same and in fact the documentation page for $orderby actually talks mostly about the sort() function that is provided.
These query modifiers that allow you to add sections of a query on without using the functional accessors do exist but there is a bug mixing these two together so I would recommend you pick either the query modifiers or the functional methods and stick to that option.
In attempting to provide example code I have also found out one other thing when I looked at your question again. You provide:
db.collection.findOne({"$query":{},"$orderby":{ "_id": -1 }})
But it is good to note that:
db.collection.findOne({}).sort({ "_id":-1})
Actually produces:
2014-07-31T04:59:50.183-0700 TypeError: Object [object Object] has no method 'sort'
and as you can see here by my test data set:
> db.rooms.find()
{ "_id" : ObjectId("53ad206e1d8f2d8351182830"), "id" : 1, "from" : ISODate("2014-06-26T00:00:00Z"), "to" : ISODate("2014-06-28T00:00:00Z") }
{ "_id" : ObjectId("53ad276f1d8f2d8351182831"), "id" : 1, "from" : ISODate("2014-06-24T00:00:00Z"), "to" : ISODate("2014-07-01T00:00:00Z") }
{ "_id" : ObjectId("53ad28ad1d8f2d8351182832"), "id" : 1, "from" : ISODate("2014-06-20T00:00:00Z"), "to" : ISODate("2014-06-28T00:00:00Z") }
{ "_id" : ObjectId("53ad28c61d8f2d8351182833"), "id" : 1, "from" : ISODate("2014-06-20T00:00:00Z"), "to" : ISODate("2014-07-03T00:00:00Z") }
{ "_id" : ObjectId("53ad29971d8f2d8351182834"), "id" : 1, "from" : ISODate("2014-06-20T00:00:00Z"), "to" : ISODate("2014-06-21T00:00:00Z") }
the answer is actually correct:
> db.rooms.findOne({ "$query":{}, "$orderby":{ "_id": -1 }})
{
"_id" : ObjectId("53ad29971d8f2d8351182834"),
"id" : 1,
"from" : ISODate("2014-06-20T00:00:00Z"),
"to" : ISODate("2014-06-21T00:00:00Z")
}
So it is interesting to note that query modifiers are supported by findOne where as functional accessors are not, which could be a reason to use query modifiers instead.

$elemmatch not working in MongoDB

I am trying to filter mongo data by using the below query in mongodb version 2.6.1 but getting error.
MongoDB version 2.4.6 (Working):
> db.BC_1839.find({data: {$elemMatch:{$where : "this.First_name.toLowerCase().indexOf('kim') ==0"}}});
output:
{
"_id" : ObjectId("53719a9d5b9e5c8c110001b9"),
"data" : [
{
"First_name" : "Kimberely",
"Last_name" : "Weyman",
"Company_name" : "Scientific Agrcltl Svc Inc",
"Address" : "7721 Harrison St",
"City" : "Kingsway West",
"State" : "NS",
"Post" : "2208",
"Phone1" : "02-7091-8948",
"Phone2" : "0441-151-810",
"Email" : "kweyman#weyman.com.au",
"Web" : "http://www.scientificagrcltlsvcinc.com.au",
"active" : "true"
}
],
"history" : [
{
"timestamp" : "2014-05-13 06:07:55",
"event": "creation",
"createdby" : "Srikesh Infotech",
"creation_data" : [
{
"crm_base_contact_id" : "1839",
"crm_imported_files_id" : "1464"
}
]
},
{
"timestamp" : "2014-05-13 06:09:05",
"event" : "Task",
"createdby" : "Srikesh Infotech",
"Task_data" : [
{
"Campaign ID" : "193",
"Campagin Name" : "Test Campa1"
}
]
}
],
"ref" : [
{ "crm_base_contact_id" : "1839", "crm_imported_files_id" : "1464" }
]
}
MongoDB version 2.6.1(Not Working):
> db.BC_1839.find({data: {$elemMatch:{$where : "this.First_name.toLowerCase().indexOf('kim') ==0"}}});
output:
error: {
"$err" : "Can't canonicalize query: BadValue $elemMatch cannot contain $
where expression",
"code" : 17287
}
Same query executes in mongodb version 2.4.6 but not in mongodb version 2.6.1 Why???
It shouldn't have worked in earlier versions at all, as at the very least you have modified the scoping of this to now refer to "data" as a top level element. In short, this is no longer allowed and you really should not be using JavaScript methods unless you absolutely have to. Even then, there is probably still a better way in most cases.
But in fact this is an un-necessary use of JavaScript matching as it is not required when there are other operators existing that will do this.
You should be using a $regex form instead:
db.docs.find({ "data.First_name": /^kim/i })
Or anywhere within the field, remove the caret ^:
db.docs.find({ "data.First_name": /kim/i })
Which is pretty much as inefficient as JavaScript execution but not as much as there is not the overhead of processing through that interpreter engine. And of course it works everywhere.
Also think about what a query relying on JavaScript to resolve is actually doing:
Invokes a JavaScript interpreter instance
Converts BSON document types per document to JavaScript types
Evaluates JavaScript code in the interpreter per document
Casts JavaScript true|false back as a result per document
Considering that $regex ( but with a case insensitive match which is not optimal ) is doing the same operations but using the "pcre" C library natively without conversion and recasting per document, then it is clearly the sane choice of the two.