MongoDb - Change type from Int to Double

We have a collection that looks like this:

{ "_id" : "10571:6", "v" : 261355, "ts" : 4.88387e+008 } 

Now some of the "v" are ints, some of them are double. I want to change them all by two.

I tried several things but nothing works (v - int32 for this entry, I want to change it to double):

 db.getCollection('VehicleLastValues') .find ( {_id : "10572:6"} ) .forEach ( function (x) { temp = xv * 1.0; db.getCollection('VehicleLastValues').save(x); }} 

Things I tried:

 xv = xv * 1.1 / 1.1; xv = parseFloat (new String(xv)); 

But I can not get it to be saved as double ...

+6
source share
1 answer

By default, all “numbers” are stored as “doubles” in MongoDB, if they are not passed in half at all.

Take the following samples:

 db.sample.insert({ "a": 1 }) db.sample.insert({ "a": NumberLong(1) }) db.sample.insert({ "a": NumberInt(1) }) db.sample.insert({ "a": 1.223 }) 

This gives a set like this:

 { "_id" : ObjectId("559bb1b4a23c8a3da73e0f76"), "a" : 1 } { "_id" : ObjectId("559bb1bba23c8a3da73e0f77"), "a" : NumberLong(1) } { "_id" : ObjectId("559bb29aa23c8a3da73e0f79"), "a" : 1 } { "_id" : ObjectId("559bb30fa23c8a3da73e0f7a"), "a" : 1.223 } 

Despite the fact that various constructor functions note that several data points look the same. The MongoDB shell itself does not always clearly differ between the two, but there is a way you can tell.

There is, of course, the $type operator, which allows you to select BSON types.

So, we test this with Type 1 - "Double":

 > db.sample.find({ "a": { "$type": 1 } }) { "_id" : ObjectId("559bb1b4a23c8a3da73e0f76"), "a" : 1 } { "_id" : ObjectId("559bb30fa23c8a3da73e0f7a"), "a" : 1.223 } 

You see that both the first insert and the last are selected, but, of course, not the other two.

So now the test for BSON Type 16 is a 32-bit integer

 > db.sample.find({ "a": { "$type": 16 } }) { "_id" : ObjectId("559bb29aa23c8a3da73e0f79"), "a" : 1 } 

This was the “third” insert that used the NumberInt() function in the shell. So the function and other serialization from your driver can set this particular type of BSON.

And for BSON Type 18, which is a 64-bit integer

 > db.sample.find({ "a": { "$type": 18 } }) { "_id" : ObjectId("559bb1bba23c8a3da73e0f77"), "a" : NumberLong(1) } 

The second insert, which was done using NumberLong() .

If you want to “rip” things that were not “double”, you would do:

 db.sample.find({ "$or": [{ "a": { "$type": 16 } },{ "a": { "$type": 18 } }]}) 

What are only other valid numeric types other than the "double" itself.

So, to “transform” them into your collection, you can use the “mass” process as follows:

 var bulk = db.sample.initializeUnorderedBulkOp(), count = 0; db.sample.find({ "$or": [ { "a": { "$type": 16 } }, { "a": { "$type": 18 } } ] }).forEach(function(doc) { bulk.find({ "_id": doc._id }) .updateOne({ "$set": { "b": doc.a.valueOf() } , "$unset": { "a": 1 } }); bulk.find({ "_id": doc._id }) .updateOne({ "$rename": { "b": "a" } }); count++; if ( count % 1000 == 0 ) { bulk.execute() bulk = db.sample.initializeUnOrderedBulkOp(); } }) if ( count % 1000 != 0 ) bulk.execute(); 

What this does is performed in three steps in bulk:

  • Enter the value in the new field as "double"
  • Delete old field with unwanted type
  • Rename the new field to the name of the old field

This is necessary because BSON type information is sticky for the field element when it was created. Therefore, to "re-enable" you need to completely delete the old data, which includes the original purpose of the field.

Thus, this should explain how to "detect" and also "re-render" unwanted types in your documents.

+7
source

All Articles