Reputation: 5095
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"
}
}
],
Upvotes: 6
Views: 11631
Reputation: 10794
You can also overwrite the toJSON method:
// Never return '__v' field and return the 'price' as String in the JSON representation
// Note that this doesn't effect `toObject`
EquityHistoryModel.set('toJSON', {
getters: true,
transform: (doc, ret) => {
if (ret.price) {
ret.price = ret.price.toString();
}
delete ret.__v;
return ret;
},
});
Upvotes: 6
Reputation: 5095
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.
Upvotes: 1