MongoDB - как насчет десятичного типа значения?

в настоящее время я изучаю и применяю MongoDB для небольшого финансового проекта.


когда я прочитала MongoDB в действии он говорит:

единственная другая проблема, которая обычно возникает с числовыми типами BSON, отсутствие десятичной поддержки. Это означает, что если вы планируете хранение значений валюты в MongoDB, необходимо использовать целочисленный тип и храните ценности в центах.


мои финансовые связанный продукт будет включать некоторые валютные значения, но я немного смущен или обеспокоен приведенным выше заявлением. Вот мои вопросы:

  1. могу ли я использовать double для тех currency values в моем проекте?
  2. что произойдет или последствия, если я напрямую использую double для них?
  3. если десятичный тип является обязательным для финансового продукта, это плохая идея использовать MongoDB?
  4. что это значит you need to use an integer type and keep the values in cents? Означает ли это, что если Я собираюсь хранить 1.34 dollars, то я должен хранить 134 cents?

спасибо

6 ответов


Если вы хотите точное представление для финансовых целей, то значения Double или floating point непригодны, поскольку дробные части подвержены ошибке округления. Некоторые десятичные значения не могут быть представлены с использованием двоичных плавающих точек и должны быть аппроксимированы.

для менее технического вступления см. проблемы с округлением чисел с плавающей запятой; если вы хотите выродок, то прочитайте Что Каждый Компьютерщик Должен Знать О Арифметика С Плавающей Запятой.

рекомендуется использовать целочисленный тип (хранить значение в центах), чтобы избежать потенциальных ошибок округления. Этот подход описывается как "использование масштабного коэффициента" в документации MongoDB для моделирование денежных данных и общее решение для MongoDB 3.2 и ранее.

MongoDB 3.4 включает в себя новый десятичный тип BSON которое обеспечивает точную точность для манипулировать поля денежных данных.


Если вы не хотите хранить валюту в виде центовых значений, вы можете хранить валюту $1.34 в качестве объекта, подобного этому:

{
    major: 1,
    minor: 34,
    currency: "USD"
}

выполнение любой математики с такими объектами будет непросто и не будет использовать коммерческие правила округления. Но вы все равно не должны делать бизнес-логику в базе данных, особенно когда это "тупая" база данных, такая как MongoDB.

что вы должны делать-это сериализовать/десериализовать эти объекты с/к Money класса в вашем приложении который реализует основные валютные математические операции с соблюдением правил округления и выдает исключение при попытке выполнить операцию с различными валютными единицами (.34 + 14.95€ = error - сначала необходимо конвертировать одну валюту в другую, указав обменный курс).


Если вы используете Мангуста, то вы можете использовать функции getter/setter в определении схемы, например

function getDecimalNumber(val) {    return (val/1000000); }
function setDecimalNumber(val) {    return (val*1000000); }

применимо к объекту схемы, например

balance: { type: Number, default: 0, get: getDecimalNumber, set: setDecimalNumber },

количество нулей для умножения / деления зависит от точности, которую вы хотите.


похоже, MongoDB наконец-то добавил поддержку десятичных знаков, хотя на момент написания статьи это только что законченная разработка, но, надеюсь, она должна быть доступна очень скоро в стабильной версии (3.4?).

https://jira.mongodb.org/browse/SERVER-1393


Я знаю, что этот пост старый, но он занимает высокие позиции в Google, так...

лучшим решением для хранения финансовых данных является использование точной точности, задокументированной самим MongoDB http://docs.mongodb.org/v2.6/tutorial/model-monetary-data/#monetary-value-exact-precision.

{price: 9990, currency: "USD" }

и когда вам нужны данные, просто разделите на 100, предполагая, что вы хотите 2-значную точность. Недостатком является то, что вам всегда нужно работать с одинаковой точностью.


MongoDb добавлена поддержка десятичный тип данных в 3.4 версии. Он также доступен из shell.

3.4 добавлена поддержка формата decimal128 с новым типом данных decimal. Формат decimal128 поддерживает числа до 34 десятичных знаков цифры (т. е. значащие цифры) и диапазон показателей от -6143 до +6144.

В отличие от типа данных double, который хранит только приближение десятичные значения, тип данных decimal хранит точное значение. Для например, десятичное число ("9.99") имеет точное значение 9.99 где в качестве двойного 9.99 будет иметь приблизительное значение 9.9900000000000002131628...