PyMongo delete document by type - mongodb

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'}})

Related

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

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/

Using $last on Mongo Aggregation Pipeline

I searched for similar questions but couldn't find any. Feel free to point me in their direction.
Say I have this data:
{ "_id" : ObjectId("5694c9eed4c65e923780f28e"), "name" : "foo1", "attr" : "foo" }
{ "_id" : ObjectId("5694ca3ad4c65e923780f290"), "name" : "foo2", "attr" : "foo" }
{ "_id" : ObjectId("5694ca47d4c65e923780f294"), "name" : "bar1", "attr" : "bar" }
{ "_id" : ObjectId("5694ca53d4c65e923780f296"), "name" : "bar2", "attr" : "bar" }
If I want to get the latest record for each attribute group, I can do this:
> db.content.aggregate({$group: {_id: '$attr', name: {$last: '$name'}}})
{ "_id" : "bar", "name" : "bar2" }
{ "_id" : "foo", "name" : "foo2" }
I would like to have my data grouped by attr and then sorted by _id so that only the latest record remains in each group, and that's how I can achieve this. BUT I need a way to avoid naming all the fields that I want in the result (in this example "name") because in my real use case they are not known ahead.
So, is there a way to achieve this, but without having to explicitly name each field using $last and just taking all fields instead? Of course, I would sort my data prior to grouping and I just need to somehow tell Mongo "take all values from the latest one".
See some possible options here:
Do multiple find().sort() queries for each of the attr values you
want to search.
Grab the original _id of the $last doc, then do a findOne() for each of those values (this is the more extensible option).
Use the $$ROOT system variable as shown here.
This wouldn't be the quickest operation, but I assume you're using this more for analytics, not in response to a user behavior.
Edited to add slouc's example posted in comments:
db.content.aggregate({$group: {_id: '$attr', lastItem: { $last: "$$ROOT" }}}).

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.