skip to Main Content

I have a question about the decimal support. I want to work with decimals and I know Mongo suggests to use Decimal128 type. It solves the rounding format on db but on the other hand I need to write decimal(BSON) to number converter getters while getting data.

I want to use decimals without changing data type. I use mongoose’s $inc, $dec operators a lot with bulk operations. If I continue to use Number(on mongoose, Double on Mongo) type, I can see very long decimals end of the some operations. For example, if I $inc 2.4 with 1.2 result will be 3.5999999999999996 (floating point numbers problem).

Is there a way to say Mongo to round selected fields’ final values’ to max 2 via mongoose model or directly on db somehow? Setters don’t work because there is no problem with 2.4 or 1.2, the problem is the result of the inc operation. Or post hooks don’t work with bulks.

Thanks in advance.

2

Answers


  1. Chosen as BEST ANSWER

    I solved this issue with change streamers. I check the post data after the any insert or update operation on specific collection. If there is a value that match with my long digit decimal pattern, updating with rounded version.

    const FORMAT_NEEDED_DECIMAL_REGEX = /^d+.d{3,}$/;
    const DECIMAL_ROUNDING_PLACE = 2;
    
    const config = [[{
      $match: { operationType: { $in: ['insert', 'update'] } },
    }], {
      fullDocument: 'updateLookup',
    }];
    
    const yourModelStream = YourModel.watch(...config);
    
    yourModelStream.on('change', (postData) => {
      const { documentKey: { _id: id }, updateDescription, operationType, fullDocument } = postData;
    
      const document = operationType === 'update' ? updateDescription.updatedFields : fullDocument;
    
      const updateQuery = Object.keys(document).reduce((acc, field) => {
        if (FORMAT_NEEDED_DECIMAL_REGEX.test(document[field])) {
          return { ...acc, [field]: { $round: [`$${field}`, DECIMAL_ROUNDING_PLACE] } };
        }
        return acc;
      }, {});
    
      if (Object.keys(updateQuery).length) {
        YourModel.updateOne({ _id: id }, [{ $set: updateQuery }]).exec().catch(() => undefined);
      }
    });
    

Please signup or login to give your own answer.
Back To Top
Search