Reputation: 473
Below is my mongoose schema
const mongoose = require('mongoose');
const AccountingCostsSchema = mongoose.Schema(
{
// other properties goes here
accountCosts: {
type: mongoose.Decimal128,
set: (v) =>
mongoose.Types.Decimal128.fromString(parseFloat(v).toFixed(4)),
required: true
}
},
{
collection: 'accountingCosts'
}
);
export = mongoose.model('AccountingCosts', AccountingCostsSchema);
Data in MongoDB
accountingCosts collection
Data in Text mode view
{
"_id" : ObjectId("4e1eb38c2bdea2fb81f5e771"),
"accountId" : ObjectId("4e8c1180d85de1704ce12110"),
"accountCosts" : NumberDecimal("200.00"),
}
Data in Text mode view
My query
db.getCollection('accountingCosts').find({'accountId': '4e8c1180d85de1704ce12110'})
Result from query
"accountCosts": {
"$numberDecimal": "123.00"
}
I tried writing a getter function on schema like i have a setter function. But it is not working
get: function(value) {
return value.toString();
}
My expected output is just a plain property with name and value like below
"accountCosts": "123.00"
Upvotes: 8
Views: 6127
Reputation: 421
I am sure you found a solution, but i will also write it here so who will land here would find a solution.
Your idea to using a getter
was right, but maybe you forgot to enable it in the schema, so let' s see how using your code.
You have this schema:
var AccountingCostsSchema = new Schema({
accountId: String,
accountCosts: {
type: Schema.Types.Decimal128,
default: 0
}
});
So when you retrieve it you will get:
{
"_id" : "12345",
"accountId" : "123456",
"accountCosts" : {
"$numberDecimal": "123.00"
}
}
Taking in example that you would get accountCosts as number, so something like that:
{
"_id" : "12345",
"accountId" : "123456",
"accountCosts" : 123
}
We would need a getter
as you said, so we will need to add a function of this getter in our model file, let' s say after your schema. This could be your getter function:
function getCosts(value) {
if (typeof value !== 'undefined') {
return parseFloat(value.toString());
}
return value;
};
Now, let' s declare this getter in our schema that will become:
var AccountingCostsSchema = new Schema({
accountId: String,
accountCosts: {
type: Schema.Types.Decimal128,
default: 0,
get: getCosts
}
});
Now mongoose will uderstand how you want that value is returned, but we have to specify that we want it uses the getter. So we have to enable it when we want to retieve the value in json format. We can simply add it as this:
var AccountingCostsSchema = new Schema({
accountId: String,
accountCosts: {
type: Schema.Types.Decimal128,
default: 0,
get: getCosts
}
}, {toJSON: {getters: true}});
And so, when you will retrieve it, you will get this:
{
"_id" : "12345",
"accountId" : "123456",
"accountCosts" : 123,
"id" : "12345"
}
But, whoa (this is not my batman glass!) what is that "id" : "12345"
?
According to Mongoose documents:
Mongoose assigns each of your schemas an id virtual getter by default which returns the document's _id field cast to a string, or in the case of ObjectIds, its hexString. If you don't want an id getter added to your schema, you may disable it by passing this option at schema construction time.
How we can avoid it? We can just add id: false
in our schema that now will be:
var AccountingCostsSchema = new Schema({
accountId: String,
accountCosts: {
type: Schema.Types.Decimal128,
default: 0,
get: getCosts
},
id: false
}, {toJSON: {getters: true}});
And now you will not see it anymore.
Just a little last tip (no, i have not finished): What happens if you have an array of objects in your schema like this?
var AccountingCostsSchema = new Schema({
accountId: String,
usersAndCosts: [{
username: String,
accountCosts: {
type: Schema.Types.Decimal128,
default: 0,
get: getCosts
}
],
id: false
}, {toJSON: {getters: true}});
Bad news now: you can not keep on using this schema. Good news now: you can fix it easly. You need to create a new schema for usersAndCosts
and then reference it in the parent schema. Let' s see it:
var usersAndCostsSchema = new Schema({
username: String,
accountCosts: {
type: Schema.Types.Decimal128,
default: 0,
get: getCosts
},
id: false
}, {toJSON: {getters: true}});
var AccountingCostsSchema = new Schema({
accountId: String,
usersAndCosts: [usersAndCostsSchema],
id: false
}, {toJSON: {getters: true}});
The result will be the same, your accountCosts
will be shown as number, no double ids.
Remember that of course this is to enable getters for toJSON
but you could need to enable them for toObject
too, as you could need to do the same for setters. But we here talked about getters for JSON.
Upvotes: 17