mongodbnode-mongodb-native

Mongo Node Driver Inserts Integer Values Instead of Doubles


I'm using the Mongo Native Javascript driver to insert data into a Mongo database. All of the docs I've read say that Mongo stores all of its numeric values as Doubles, and Javascript also stores all of its numerics as doubles. I can confirm that this works in the shell:

PRIMARY> db.products.insertOne({id: 10, price: 10})
PRIMARY> db.products.insertOne({id: 11, price: 11.99})

PRIMARY> db.products.aggregate([{$project: { price: {$type: "$price"}}}])
{ "_id" : ObjectId("605525ed8f87f3c9bc136a69"), "price" : "double" }
{ "_id" : ObjectId("605525fb8f87f3c9bc136a6a"), "price" : "double" }

However, when I insert values from the Javascript driver, they are not all doubles, but instead the integer-looking number is stored with a bsontype of int:

-- Node
  await products.insertOne({id: 1, price: 20});
  await products.insertOne({id: 2, price: 20.85});

--Mongo Shell
PRIMARY> db.products.aggregate([{$project: { price: {$type: "$price"}}}])
{ "_id" : ObjectId("6055261ee2efe2622736a36e"), "price" : "int" }
{ "_id" : ObjectId("6055261ee2efe2622736a36f"), "price" : "double" }

Is there a way in the mongo js driver to force it to always store numbers as doubles? I am ultimately reading this into a Java program which really wants the incoming types to be consistent, so if I can make them that way on insert I'd like to do that.


Solution

  • Option 1

    You can use https://plugins.mongoosejs.io/plugins/double

    const Double = require('@mongoosejs/double');
    
    const productsSchema = new Schema({ price: Double });
    
    console.log(new Double(5));
    
    Output - Double {
      path: 5,
      instance: 'Double',
      validators: [],
      getters: [],
      setters: [],
      options: SchemaTypeOptions {},
      _index: null,
      [Symbol(mongoose#schemaType)]: true }
    

    You can check the source code here

    https://github.com/mongoosejs/mongoose-double/blob/master/lib/index.js


    Option 2

    You can use mongoose.Decimal128-

    https://mongoosejs.com/docs/api.html#mongoose_Mongoose-Decimal128

    const productsSchema = new Schema({ price: mongoose.Decimal128 });
    
    Insert query will be like this -"price":{"$numberDecimal":"5"}
    

    The Mongoose Decimal128 SchemaType. Used for declaring paths in your schema that should be 128-bit decimal floating points. Do not use this to create a new Decimal128 instance, use mongoose.Types.Decimal128 instead.

    https://jira.mongodb.org/browse/SERVER-854


    https://docs.mongodb.com/manual/core/shell-types/#numberint

    https://docs.mongodb.com/manual/core/shell-types/#numberdecimal

    The mongo shell treats all numbers as 64-bit floating-point double values by default. The mongo shell provides the NumberDecimal() constructor to explicitly specify 128-bit decimal-based floating-point values capable of emulating decimal rounding with exact precision. This functionality is intended for applications that handle monetary data, such as financial, tax, and scientific computations.

    Mongo shell default insertion for the number is double to insert int we have to typecast using NumberInt

    db.data.insertOne({ "numDouble":20.87,  "numInt": NumberInt(1) })
    

    https://github.com/Studio3T/robomongo/issues/622


    Another option not sure it will work.

    https://mongodb.github.io/node-mongodb-native/api-bson-generated/double.html

    typecast the value to Double while inserting the value

    const Double = require("mongodb").Double;
    
    await products.insertOne({id: 1, price: Double(20) });
    console.log(new Double(5))
    
    Output - Double { _bsontype: 'Double', value: 5 }
    

    A class representation of the BSON Double type. class Double()

    Arguments:
    value (number) – the number we want to represent as a double. Returns: double