Skip to content

Modeling Monetary Data in MongoDB #1858

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions source/tutorial/model-monetary-data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
===================
Model Monetary Data
===================

.. default-domain:: mongodb

Overview
--------

While applications that handle monetary data must conform to regulatory or
other requirements for arithmetic performed on monetary values, the binary
floating point arithmetic used in modern hardware and in MongoDB does not
conform to regulations for monetary arithmetic.

Fractional numeric quantities common to monetary problems have no exact
representation in binary floating point numbers. MongoDB has no built-in
support for storing numeric data except as IEEE 754 standard 64-bit
floating point numbers, and as 32-bit and 64-bit signed integers.

This document describes two ways to handle monetary data in MongoDB:

- Create two fields, one to store the exact monetary value and a
second field to store monetary data as a floating point approximation.

- Multiply the monetary value by a power of 10 then store the value in a
single field.

Pattern
-------

Model monetary data based on whether or not arbitrary precision is
acceptable, for example, if there is no need to perform mathematical
manipulations of monetary data.

Arbitrary Precision
~~~~~~~~~~~~~~~~~~~

If arbitrary precision is acceptable, store monetary data as an embedded
MongoDB document with two fields:

1. In one field, encode the exact monetary value as a non-numeric data
type, for example, ``BinData`` or a ``string``.

#. In the second field, store a double-precision floating point
approximation of the exact value. Use data from this field for server-side
range and sort queries.

The following is an example document using two fields to store the amount
``$9.99``:

.. code-block:: sh

{ display_price : "9.99", approx_price : 9.9900000000000002 }

The second field allows an application to retrieve and sort data based on
the monetary value. Careful range and sort queries to access documents
also are possible.

However, applications will need to perform client-side post-processing of documents
retrieved based on the decoding of the opaque representation of the exact
monetary value.

Because the exact monetary value is stored as an additional object, it may
be difficult to perform calculations on these values without first
manipulating the data. If you do not expect to regularly perform
calculations on the data, then this method provides the most descriptive
resolution.

Exact Precision
~~~~~~~~~~~~~~~

If your use case cannot support arbitrary precision, or you need to
regularly perform calculations on monetary data, store these data as a
single value in a MongoDB document.

1. Determine the maximum precision needed, for example, to the tenth of
one cent.

#. Multiply the monetary value to an integer by scaling to a power of 10.
For one tenth of one cent, for example, multiply the monetary value by
1000.

#. Assign this value to a field.

The power of 10 must be large enough for the smallest unit of monetary
relevance to become the least significant digit in the integral value.

The following is an example document using a single field with the amount
of ``$9.99`` scaled to a power of 10:

.. code-block:: sh

{ price : 9990 }