Mongodb can't find object with too long _id - mongodb

I have a little bit strange situation.
I persist objects in collection "refs" explicitly setting _id.
So I have objects with very big id's.
db.refs.find().sort({_id: -1});
// {_id: 9200000000165761625}
// ...
But when I try to find object with biggest id in mongo shell it returns nothing:
db.refs.find({_id: 9200000000165761625}); // nothing
But!
db.refs.find({_id: 9200000000165761625}).count(); // return 1
How could this happen?

i could not reproduce your problem. i was able to successfully query on the _id value you specified.
ensure that when you are querying you are passing correct collection name

JavaScript currently only has a single numeric type Number, which represents all values as 64-bit floating point values. The maximum safe integer representation in JavaScript's native Number type is 253-1 or 9007199254740991 (as returned by the constant Number.MAX_SAFE_INTEGER).
Any integer values beyond the safe range cannot be represented distinctly, so two or more mathematical values will map to the same JavaScript Number.
You can see this effect in the mongo shell with values adjacent to your provided _id (which is larger than the safe integer size):
> 9200000000165761624
9200000000165762000
> 9200000000165761625
9200000000165762000
> 9200000000165761626
9200000000165762000
However, these driver/client limitations are distinct from the underlying data types used in MongoDB's BSON format for documents. BSON has a 64-bit integer type which represents the full range of values: up to 263-1 for 64-bit integers.
Your example _id is within the 64-bit integer range so you should be able to insert or update this using a driver with support for 64-bit integers, but would not be able to safely query or manipulate long values in the mongo shell or other JavaScript environments. To avoid unexpected outcomes you may want to use a different data type for these long _id values.

Related

MongoDB Compass : can't filter a specific ID

I have a MongoDB Collection build like this :
When I try to filter by ID, I got inconsistent results. For exemple, when I try to get the first entry, by typing in filter query :
{_id:209383449381830657}
I got no result found.
But if I type for exemple the third, It work correctly.
{_id:191312485326913536}
I searched if it's due to too large int but no, all _id value are Int64 and it's the same code that generate all entries.
I really don't know why I got this result and that why I am asking here.
EDIT:
All entries have same type.
No limit are set in query.
If I type {_id:{"$gte":209383449381830657}} it found the entry, but don't if I type {_id:{"$eq":209383449381830657}}
MongoDB Compass uses mongo's node.js driver.
Both 209383449381830657 and 191312485326913536 exceed the javascript max safe integer of (2^53-1).
Javascript does not handle numbers larger than that in a consistent manner.
Note that in your documents, those numbers are reported as $numberLong, indicating that they are not using javascript's default floating point numeric representation.
To query these number consistently, use the NumberLong constructor when querying, like
{_id:NumberLong("209383449381830657")}
It depends on the version of MongoDB Compass you have (I assume it's +- latest)
As I see, you are using NumberLong for _id field.
You might use NumberLong("...") to handle such fields in MongoDB.
So, better to try search like this
{_id: NumberLong("209383449381830657")}
Can't say for sure how MongoDB Compass handles number you are trying to pass here.
As it should automatically cast values to int32 or int64, but it might be a bit tricky. So, better to define it by yourself to avoid unexpected results.
Some time ago I read an article that it tries to cast to int32, but if it's more than int32 might handle -> then it uses this function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger
and tries to cast it to int64. My speculation is that problem lives here, but can't say for sure.
In my case the _id contain hex digits.
Filter {_id: ObjectId("62470af3036b9f058552032e")} works

How does mongodb support sorting over multiple keys?

Sorting on Key1 first and then Key2 isn't the same as sorting on Key2 first then Key1. Mongodb just receives sort order object like {"key1":-1, "key2":1}.
How does it guarantee it does what the programmer wants?
There are many bindings to the mongodb driver where many programming languages have some kind of hashmap implemented, and they are likely to not reserve key order. If one uses some kind of hashmap to talk to the mongodb driver, how is the sorting key precedence by the order of insertion of keys into such hashmap guaranteed?
As far I know there's no way to force mongodb's comparison for the sort to use a specific comparator expression. Sorting happens as follows
When comparing values of different BSON types, MongoDB uses the following comparison order, from lowest to highest:
MinKey (internal type)
Null
Numbers (ints, longs, doubles)
Symbol, String
Object
Array
BinData
ObjectId
Boolean
Date
Timestamp
Regular Expression
MaxKey (internal type)

MongoDB datatype handling

Is there a way to handle numbers, which are stored as strings, like integers in mongodb?
e.g.
{
"someKey" : "45646764646"
}
I would like to perform $gte or $lte operations on that value, but it's not possible as long the value for "someKey" is a string. I also would like to avoid of using a dbcursor and make comparisons with java e.g.
If your field someKey contains numbers, consider saving it as NumberLong() . Your driver should allow you to represent that field in your application as a string on most all 10gen drivers.
I would recommend, if possible, converting the strings to ints when you store them in the database. This could prevent confusion in the future, and would save a lot of space due to the storage differences.

Does MongoDB's Map/Reduce always return results in floats?

I am using Mongoid, which is on top of the Ruby MongDB driver. Even though my Map's emit is giving out a parseInt(num), and the Reduce's return is giving back also a parseInt(num), the final results still are floats.
Is that particular to MongoDB? Any way to make it integer instead?
The parseInt function officially takes a string as parameter. This string is parsed as if it were an integer, thus ignoring everything after the first non-numeric character. If you provide a floating point number, it will be converted to a string before it is parsed.
The parseInt functions returns a Number, not an integer. Number is the only numeric data type in JavaScript; there is no distinction between integers and floats.
So while parseInt will remove any decimals, the data type doesn't change. Therefore Mongoid doesn't know whether to treat the result as a float or an integer. You're responsible for converting the result to an integer, as you can see in this example.
Update
I came across the NumberLong type, which represents a 64-bit integer. If you return new NumberLong(num) from your reduce function, Mongoid may treat it as an integer type.
Note that you'll need MongoDB 1.6 for this to work in the MongoDB Shell. I don't know whether Mongoid supports it yet.

How to set the hilo sequence starting value in MongoDB Norm?

i imported a lot of existing values into my mongodb via the norm driver (including the "old" id - integer value). Now i got duplicate key errors from time to time.
To solve this, i have to set the starting value for the hilo sequence manually. How can this be done?
Thanks in advance
The HiLo key information is stored in the NormHiLoKey collection. You can increment the value in this collection to change the starting value of the generated keys, using the following command in the Mongo shell:
db.NormHiLoKey.update({ _id: "nameOfCollection" }, { $inc: { ServerHi: 42 } })
CAUTION
Do not set the ServerHi value from the Mongo shell! The ServerHi is stored as a 64 bit integer, which cannot be represented in the shell. So if you set the value from the shell, it will change the underlying data type and break the NoRM deserializer.
If you run the db.NormHiLoKey.find() command, you'll likely see objects with floatApprox properties. This is an indication that the underlying data type is a 64 bit integer. By using the $inc operator you can safely modify the value, without accidentally breaking anything.