MongoDB - co z typem dziesiętnym wartości?

Obecnie uczę się i aplikuję MongoDB do małego projektu finansowego.


Kiedy czytam MongoDB w akcji , pisze:

Jedyną inną kwestią, która często pojawia się przy typach liczbowych BSON, jest brak obsługi dziesiętnej. Oznacza to, że jeśli planujesz zapisując wartości waluty w MongoDB, musisz użyć typu integer i zachowaj wartości w centach.


Mój produkt związany z finansami będzie obejmować kilka wartości waluty, ale jestem trochę zdezorientowany lub martwię się powyższym stwierdzeniem. Oto moje pytania:

  1. Czy mogę użyć double dla tych currency values w moim projekcie?
  2. co się stanie lub jakie będą konsekwencje, jeśli użyję bezpośrednio double dla nich?
  3. Jeśli typ dziesiętny jest obowiązkowym elementem produktu finansowego, czy używanie MongoDB jest złym pomysłem?
  4. Co to znaczy you need to use an integer type and keep the values in cents? Czy to znaczy, że jeśli mam przechowywać 1.34 dollars, to powinienem przechowywać 134 cents?

Dzięki

Author: Jackson Tale, 2012-07-18

6 answers

Jeśli chcesz dokładnej reprezentacji dla celów finansowych, to wartości podwojone lub zmiennoprzecinkowe są nieodpowiednie, ponieważ części ułamkowe podlegają błędowi zaokrąglenia. Niektóre wartości dziesiętne nie mogą być reprezentowane za pomocą binarnych zmiennoprzecinkowych i muszą być przybliżone.

Dla mniej technicznego wstępu Zobacz problem z zaokrąglaniem liczb zmiennoprzecinkowych ; Jeśli chcesz się wykręcić, przeczytaj co każdy informatyk powinien wiedzieć o zmiennoprzecinkowych Arytmetyka .

Zaleca się użycie typu integer (przechowującego wartość w centach), aby uniknąć potencjalnych błędów zaokrąglania. Podejście to jest opisane jako " przy użyciu współczynnika skali " w dokumentacji MongoDB dla modelowania danych pieniężnych i jest ogólnym obejściem dla MongoDB 3.2 i wcześniejszych.

MongoDB 3.4 zawiera nowy dziesiętny Typ BSON , który zapewnia dokładną precyzję manipulowania polami danych monetarnych.

 29
Author: Stennie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-24 09:52:40

Jeśli nie chcesz przechowywać waluty jako wartości centów, możesz przechowywać walutę o wartości $1.34 jako obiekt podobny do tego:

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

Robienie jakichkolwiek obliczeń z takimi obiektami nie byłoby łatwe i nie używałoby komercyjnych reguł zaokrąglania. Ale i tak nie powinieneś robić żadnej logiki biznesowej w bazie danych, zwłaszcza, gdy jest to" głupia " baza danych, taka jak MongoDB.

To, co powinieneś zrobić, to serializować / deserializować te obiekty z / do klasy Money w Twojej aplikacji, która implementuje podstawowe operacje matematyczne waluty przestrzegające zasad zaokrąglania i rzucają wyjątek, gdy próbujesz wykonać operację z różnymi jednostkami walutowymi ({[2] } - najpierw musisz przeliczyć jedną walutę na drugą walutę, podając kurs wymiany).

 5
Author: Philipp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-20 13:16:23

Jeśli używasz Mongoose, możesz użyć funkcji getter/setter w definicji schematu, np.

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

Dotyczy obiektu schematu, takiego jak

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

Liczba zer do mnożenia/dzielenia przez zależy od żądanej dokładności.

 4
Author: HNyang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-16 22:04:58

Wygląda na to, że MongoDB w końcu dodał wsparcie dla dziesiętnych, chociaż w momencie pisania tego jest to właśnie ukończony rozwój, ale mam nadzieję, że wkrótce będzie dostępny w stabilnej wersji (3.4?).

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

 4
Author: arva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-09 05:51:53

Wiem, że ten post jest stary, ale plasuje się wysoko w Google tak...

Najlepszym rozwiązaniem do przechowywania danych finansowych jest użycie dokładnej precyzji, jak udokumentowali sami MongoDB tutaj http://docs.mongodb.org/v2.6/tutorial/model-monetary-data/#monetary-value-exact-precision.

{price: 9990, currency: "USD" }

A kiedy potrzebujesz danych po prostu podziel przez 100 zakładając, że chcesz 2-cyfrową precyzję. Minusem jest to, że zawsze musisz pracować z taką samą precyzją.

 2
Author: heavenleft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-09 12:10:58

MongoDb dodał wsparcie dla dziesiętnego typu danych w wersji 3.4 . Jest również dostępny z powłoki .

3.4 dodaje obsługę formatu decimal128 z nowym typem danych decimal. Format decimal128 obsługuje liczby z dokładnością do 34 dziesiętnych cyfry (tj. cyfry znaczące) i zakres wykładniczy od -6143 do +6144.

W przeciwieństwie do typu danych double, który przechowuje tylko przybliżenie wartości dziesiętne, typ danych decimal przechowuje dokładna wartość. Na przykład, liczba dziesiętna ("9.99") ma dokładną wartość 9.99 gdzie jako podwójne 9,99 miałoby przybliżoną wartość 9.9900000000000002131628...

 2
Author: Salvador Dali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-06 02:05:48