Matt Goodrich Matt Goodrich - 6 months ago 58
Node.js Question

Extract Decimal from NumberDecimal with Mongo(ose)

In the Numeric Model for storing monetary values, the MongoDB docs state:


From the mongo shell decimal values are assigned and queried using the NumberDecimal() constructor.


Similarly, when using the Morphia Java library, BigDecimals are automatically inserted as BigDecimals.

I'm querying Mongo in Node with Mongoose and attempting to extract the numeric value of a field stored as a NumberDecimal. However, the value is oddly wrapped in query results and I'm not sure how to extract it through Mongo or Mongoose:

[
{
"openValue":{
"$numberDecimal":"119.931"
},
"timestamp":"2017-01-20T10:30:00.000Z"
},
{
"openValue":{
"$numberDecimal":"119.965"
},
"timestamp":"2017-01-20T10:31:00.000Z"
}
]


One post I read stated using
parseFloat()
in my application code will perform what I desire, however it's not efficient to iterate through the result to perform this transformation. Avoiding iterating and transforming would mean running the function on the NumberDecimals whenever I want their value every time, which would be annoying.

Is there a way I can use Mongo or Mongoose to convert the above JSON query-result into what's below?

[
{
"openValue": 119.931,
"timestamp":"2017-01-20T10:30:00.000Z"
},
{
"openValue": 119.965,
"timestamp":"2017-01-20T10:31:00.000Z"
},
{
"openValue": 119.975,
"timestamp":"2017-01-20T10:32:00.000Z"
}
]


I tried selecting the field as
...openValue.$numberDecimal
, but this didn't work. Thank you!

Edit: Here's my Mongoose schema:

var EquityHistoryModel = new Schema({
_id: {
equityIdentifier: { type: {
exchange: { type: String, index: true },
symbol: { type: String, index: true }
}, index: true },
instant: { type: Date, index: true },
durationMinutes: { type: Number }
},
open: { type: mongoose.Schema.Types.Decimal },
high: { type: mongoose.Schema.Types.Decimal },
low: { type: mongoose.Schema.Types.Decimal },
close: { type: mongoose.Schema.Types.Decimal },
volume: { type: Number },
isDividendAdjusted: { type: Boolean },
isSplitAdjusted: { type: Boolean }
}, { collection: 'equityHistories', versionKey: false });


Here's the Mongoose query for the first JSON result above:

mongo.EquityHistoryModel.aggregate([
{
"$match":{
"_id.equityIdentifier.exchange":passed_in,
"_id.equityIdentifier.symbol":passed_in,
"_id.instant":passed_in
}
},
{
"$project":{
"_id":0,
"openValue":"$open",
"timestamp":"$_id.instant"
}
}
],

Answer Source

Contrary to what I expected, it seems the values are automatically extracted. Stringifying the result automatically wraps the value in the NumberDecimal. See the code with the output manually placed below:

console.log(docs[0].openValue);
119.800
console.log(JSON.stringify(docs[0].openValue]);
{"$numberDecimal":"119.800"}

Also, I struggled with sending query results, due to res.json or res.send using stringify. Instead I wrote a replace function and set the property in Node.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download