Cast field in pymongo query - mongodb

I feel like this should be trivial.
I have a record like :
{'f1' : 1, 'f2' , 'aaaa'}
When I query for that I want to be returned :
{'f1' : '1', 'f2' , 'aaaa'}
Where I have simply cast the int as a string. I don't believe I should have to use the aggregation framework to accomplish this.
I imagine there is someway to pass a JS function but I don't know that magic.
Edit:
Answering my own question to some degree.To do this with aggregation framework. It would be as simple as.
db.datasets.aggregate({$match : {f1:{$ne:null}}},{ $project : {f1: {$toUpper:"$f1"}, f2 : 1 }})

Neither MongoDB nor PyMongo provides a feature like this. You could try adding a "SON manipulator" to transform the outgoing document (that is, the document being retrieved out of the database). But by far the easiest method is:
for doc in db.datasets.find():
doc['f1'] = str(doc['f1'])
do_something_with(doc)

Related

Finding an object ID embedded in an array [duplicate]

I've found this question answered for C# and Perl, but not in the native interface. I thought this would work:
db.theColl.find( { _id: ObjectId("4ecbe7f9e8c1c9092c000027") } )
The query returned no results. I found the 4ecbe7f9e8c1c9092c000027 by doing db.theColl.find() and grabbing an ObjectId. There are several thousand objects in that collection.
I've read all the pages that I could find on the mongodb.org website and didn't find it. Is this just a strange thing to do? It seems pretty normal to me.
Not strange at all, people do this all the time. Make sure the collection name is correct (case matters) and that the ObjectId is exact.
Documentation is here
> db.test.insert({x: 1})
> db.test.find() // no criteria
{ "_id" : ObjectId("4ecc05e55dd98a436ddcc47c"), "x" : 1 }
> db.test.find({"_id" : ObjectId("4ecc05e55dd98a436ddcc47c")}) // explicit
{ "_id" : ObjectId("4ecc05e55dd98a436ddcc47c"), "x" : 1 }
> db.test.find(ObjectId("4ecc05e55dd98a436ddcc47c")) // shortcut
{ "_id" : ObjectId("4ecc05e55dd98a436ddcc47c"), "x" : 1 }
If you're using Node.js:
var ObjectId = require('mongodb').ObjectId;
var id = req.params.gonderi_id;
var o_id = new ObjectId(id);
db.test.find({_id:o_id})
Edit: corrected to new ObjectId(id), not new ObjectID(id)
Even easier, especially with tab completion:
db.test.find(ObjectId('4ecc05e55dd98a436ddcc47c'))
Edit: also works with the findOne command for prettier output.
You Have missed to insert Double Quotes.
The Exact Query is
db.theColl.find( { "_id": ObjectId("4ecbe7f9e8c1c9092c000027") } )
If you are working on the mongo shell, Please refer this : Answer from Tyler Brock
I wrote the answer if you are using mongodb using node.js
You don't need to convert the id into an ObjectId. Just use :
db.collection.findById('4ecbe7f9e8c1c9092c000027');
this collection method will automatically convert id into ObjectId.
On the other hand :
db.collection.findOne({"_id":'4ecbe7f9e8c1c9092c000027'}) doesn't work as expected. You've manually convert id into ObjectId.
That can be done like this :
let id = '58c85d1b7932a14c7a0a320d';
let o_id = new ObjectId(id); // id as a string is passed
db.collection.findOne({"_id":o_id});
I think you better write something like this:
db.getCollection('Blog').find({"_id":ObjectId("58f6724e97990e9de4f17c23")})
Once you opened the mongo CLI, connected and authorized on the right database.
The following example shows how to find the document with the _id=568c28fffc4be30d44d0398e from a collection called “products”:
db.products.find({"_id": ObjectId("568c28fffc4be30d44d0398e")})
I just had this issue and was doing exactly as was documented and it still was not working.
Look at your error message and make sure you do not have any special characters copied in. I was getting the error
SyntaxError: illegal character #(shell):1:43
When I went to character 43 it was just the start of my object ID, after the open quotes, exactly as I pasted it in. I put my cursor there and hit backspace nothing appeared to happen when it should have removed the open quote. I hit backspace again and it removed the open quote, then I put the quote back in and executed the query and it worked, despite looking exactly the same.
I was doing development in WebMatrix and copied the object id from the console. Whenever you copy from the console in WebMatrix you're likely to pick up some invisible characters that will cause errors.
In MongoDB Stitch functions it can be done using BSON like below:
Use the ObjectId helper in the BSON utility package for this purpose like in the follwing example:
var id = "5bb9e9f84186b222c8901149";
BSON.ObjectId(id);
For Pythonists:
import pymongo
from bson.objectid import ObjectId
...
for row in collectionName.find(
{"_id" : ObjectId("63ae807ec4270c7a0b0f2c4f")}):
print(row)
To use Objectid method you don't need to import it. It is already on the mongodb object.
var ObjectId = new db.ObjectId('58c85d1b7932a14c7a0a320d');
db.yourCollection.findOne({ _id: ObjectId }, function (err, info) {
console.log(info)
});
Simply do:
db.getCollection('test').find('4ecbe7f9e8c1c9092c000027');

MongoDB - Find documents which contain an element in an array which has a property of null

I'm struggling with a seemingly simple query in mongodb.
I have a job collection that has objects like:
{
"_id" : ObjectId("5995c1fc3c2a353a782ee51b"),
"stages" : [
{
"start" : ISODate("2017-02-02T22:06:26Z"),
"end" : ISODate("2017-02-03T22:06:26Z"),
"name" : "stage_one"
},
{
"start" : ISODate("2017-02-03T22:06:26Z"),
"end" : ISODate("2017-02-07T20:34:01Z"),
"name" : "stage_two"
}
]
}
I want to get a job whose second stage does not have an end time, i.e. end is null or not defined.
According to the mongo docs on querying for null and querying an array of embedded documents, it would seem the correct query should be:
db.job.findOne({'stages.1.end': null})
However, running that query returns me the job above which does have a non-null end date. In fact, if I run the query with count instead of findOne, I see that all jobs are returned - no filtering is done at all.
For completeness, here is the output from an example on a fresh mongo instance:
So in this example, I would expect db.job.findOne({'stages.1.end': null}) to return nothing since there is only one document and its second stage has a non-null end date.
This feels like the sort of issue where it's just me being an idiot and if so, I apologise profusely.
Thanks in advance for your help and let me know if you need any more details!
EDIT:
After some more experimentation, I think I can achieve what I want with the following:
db.job.find({$or: [{'stages.1.end': { $type: 10 }}, {'stages.1.end': {$exists: false}}]})
While this gets the job done, it doesn't feel like the simplest way and I still don't understand why the original query doesn't work. If anyone could shed some light on this it'd be much appreciated.

mongodb query mixing timestamps and ISODates

I have a mongodb collection containing docs with both ISODates and timestamps in them, something like this:
doc = {
"_id" : ObjectId(...),
"updated" : 1445939778450,
"delivered" : ISODate("2016-12-21T09:40:29.082Z")
...
}
how can I compare updated and delivered fields using $where?
That's a great question! :)
It seems that mongodb handles this conversion automatically when using $where, so simply query like this:
db.my_collection.find({ $where : "this.updated > this.delivered" })
(if someone can point to documentation about this feature, please add)

Querying sub array with $where

I have a collection with following document:
{
"_id" : ObjectId("51f1fd2b8188d3117c6da352"),
"cust_id" : "abc1234",
"ord_date" : ISODate("2012-10-03T18:30:00Z"),
"status" : "A",
"price" : 27,
"items" : [{
"sku" : "mmm",
"qty" : 5,
"price" : 2.5
}, {
"sku" : "nnn",
"qty" : 5,
"price" : 2.5
}]
}
I want to use "$where" in the fields of "items", so something like this:
{$where:"this.items.sku==mmm"}
How can I do it? It works when the field is not of array type.
You don't need a $where operator to do this; just use a query object of:
{ "items.sku": mmm }
As for why your $where isn't working, the value of that operator is executed as JavaScript, so that's not going to check each element of the items array, it's just going to treat items as a normal object and compare its sku property (which is undefined) to mmm.
You are comparing this.items.sku to a variable mmm, which isn't initialized and thus has the value unefined. What you want to do, is iterate the array and compare each entry to the string 'mmm'. This example does this by using the array method some which returns true, when the passed function returns true for at least one of the entries:
{$where:"return this.items.some(function(entry){return entry.sku =='mmm'})"}
But really, don't do this. In a comment to the answer by JohnnyHK you said "my service is just a interface between user and mongodb, totally unaware what the field client want's to store". You aren't really explaining your use-case, but I am sure you can solve this better.
The $where operator invokes the Javascript engine even though this
trivial expression could be done with a normal query. This means unnecessary performance overhead.
Every single document in the collection is passed to the function, so when you have an index, it can not be used.
When the javascript function is generated from something provided by the client, you must be careful to sanetize and escape it properly, or your application gets vulnerable to code injection.
I've been reading through your comments in addition to the question. It sounds like your users can generically add some attributes, which you are storing in an array within a document. Your client needs to be able to query an arbitrary pair from the document in a generic manner. The pattern to achieve this is typically as follows:
{
.
.
attributes:[
{k:"some user defined key",
v:"the value"},
{k: ,v:}
.
.
]
}
Note that in your case, items is attributes. Now to get the document, your query will be something like:
eg)
db.collection.find({attributes:{$elemMatch:{k:"sku",v:"mmm"}}});
(index attributes.k, attributes.v)
This allows your service to provide a way to query the data, and letting the client specify what the k,v pairs are. The one caveat with this design is always be aware that documents have a 16MB limit (unless you have a use case that makes GridFS appropriate). There are functions like $slice which may help with controlling this.

use $lt or $gt operator in mongodb queries

My collection structure*"countcollection"* is looks as below
{
"limitcount": 10000,
"currentcount": 100
}
I want to right the mongoquery that able to compare the currentcount<($lt)limitcount
or currentcount>($gt)limitcount.
First, i wrote the mongo query as below
db.countcollection.find({"currentcount":{$lt:{"limitcount"}}});
db.countcollection.find({"currentcount":{$gt:{"limitcount"}}});
but it's failed to execute .
please give your input for this mongoquery.
thanks in advance .
javaamtho.
As Bugai13 said, you can't do a comparison on 2 fields in a query.
The problem with $where is performance - as that is a javascript function that will be executed for every document so it will have to scan through every one.
So, you could store another field (that you could then index) alongside those existing fields
e.g.
{
"limitcount": 10000,
"currentcount": 100,
"remainingcount" : 9900
}
so you could then query on the new field instead:
db.countcollection.find({"remainingcount" : {$gt : 0}})
db.countcollection.find({"remainingcount" : {$lt : 0}})
You can't do what you want using simple query(like you have tried above). There is such bug in mongodb jira and you can vote up for this.
I suppose you shoud use javascript expression like this:
db.countcollection.find( { $where: "this.currentcount < this.limitcount" } );
Hope this help.
$gt:{"limitcount"}}
does not make any sense since you are comparing against the string limitcount. If you want to compare against a pre-defined variable, use the variable but something with quotes around it. Why did you choose this strange syntax?