बड़े पूर्णांक प्रिसिज़न क्यों खो देते हैं
मुख्य बात: 2^53-1 से ऊपर के पूर्णांक JSON.parse में प्रिसिज़न खो देते हैं। Snowflake IDs, ऑर्डर नंबर और डेटाबेस bigints सब इससे गुज़रते हैं, इसलिए उन्हें शुरू से अंत तक स्ट्रिंग के रूप में रखें।

मुख्य बात: snowflake IDs, ऑर्डर नंबर और bigint प्राइमरी कुंजियों को सीरियलाइज़ेशन, ट्रांसपोर्ट और पार्सिंग के दौरान स्ट्रिंग के रूप में रखें; संख्यात्मक टाइप तभी रखें जब फ़ील्ड 2^53-1 के भीतर साबित हो, और तब Schema में maximum constraint से उसे लागू करें।
क्योंकि नुकसान पार्सिंग के दौरान होता है, चुपचाप।
JSON.parse('{"id": 9007199254740993}');
// { id: 9007199254740992 }
गायब अंक चला गया; वापस पाने के लिए कुछ नहीं है।
2^53 कहाँ से आता है
JavaScript में एक संख्यात्मक टाइप है: IEEE 754 double precision, 53 बिट significand के साथ (एक implicit, 52 explicit)। इसलिए सटीक पूर्णांक ±(2^53-1) पर रुक जाते हैं:
-9007199254740991 .. 9007199254740991
उस रेखा से ऊपर, क्रमागत निरूपित होने योग्य मान 2, 4, 8 के अंतर पर होते हैं। 9007199254740993 विषम है, और उस परिमाण पर हर निरूपित होने योग्य मान सम है, इसलिए यह 9007199254740992 पर राउंड हो जाता है।
किन फ़ील्ड पर असर पड़ता है
| फ़ील्ड | अंक | जोखिम |
|---|---|---|
| Snowflake IDs | 18–19 | उच्च, अंतिम अंक बदलते हैं |
| ऑर्डर / लेनदेन नंबर | 16–20 | उच्च |
| डेटाबेस bigint प्राइमरी कुंजियाँ | 19 | उच्च |
| Minor units में धनराशि | — | निम्न |
| मिलीसेकंड टाइमस्टैम्प | 13 | सुरक्षित |
साझा सूत्र: ये पहचानकर्ता हैं, मात्राएँ नहीं। पहचानकर्ता केवल भेजा जाता है, उसमें कभी जोड़ या गुणा नहीं होता, इसलिए स्ट्रिंग सही टाइप है।
चार समाधान
स्ट्रिंग के रूप में सीरियलाइज़ करें। बैकएंड रिस्पॉन्स लिखने से पहले bigint फ़ील्ड बदल देता है। सरल और टिकाऊ; दर्ज करें कि ये फ़ील्ड स्ट्रिंग हैं।
सीरियलाइज़र को संभालने दें। Jackson का Long के लिए ToStringSerializer, Go का json:",string" टैग। वही विचार: मान को संख्यात्मक रास्ते से बाहर रखें।
BigInt समर्थन के साथ पार्स करें। json-bigint और इसी तरह की लाइब्रेरी। ध्यान दें कि BigInt को Number अंकगणित के साथ नहीं मिलाया जा सकता, और JSON.stringify इसे अस्वीकार करता है।
सीमा निर्धारित करें। अगर फ़ील्ड वाकई 2^53 से अधिक नहीं हो सकता, तो Schema में maximum जोड़ें ताकि सीमा से बाहर डेटा ब्राउज़र में चुपचाप विफल होने के बजाय वैलिडेशन में विफल हो।
यह बग है या नहीं कैसे पता करें
एक ज्ञात ID लें और उसे round-trip करें: सीरियलाइज़ करें, भेजें, पार्स करें, अक्षर-दर-अक्षर तुलना करें। या कच्चा रिस्पॉन्स body देखें — 19 अंकों वाली बिना कोट की संख्या जो गलत अंतिम अंकों के साथ आए, लगभग निश्चित रूप से parse-time loss है।
FAQ
JSON.parse अंतिम अंक बिना एरर क्यों बदल देता है?
JavaScript में एक संख्यात्मक टाइप है, IEEE 754 double precision, इसलिए 2^53-1 से ऊपर के पूर्णांक केवल निकटतम निरूपित होने योग्य मान पर पहुँच सकते हैं। JSON.parse इसे सामान्य संख्यात्मक रूपांतरण मानता है: न throw करता है न चेतावनी देता है।
फ़्रंटएंड बड़े पूर्णांक सही कैसे रख सकता है?
json-bigint जैसी लाइब्रेरी उपयोग करें, क्योंकि JSON.parse यह नहीं कर सकता। कीमत यह है कि BigInt को Number अंकगणित के साथ नहीं मिलाया जा सकता और JSON.stringify इसे अस्वीकार करता है, इसलिए आसपास का कोड भी बदलना पड़ता है।
क्या API दस्तावेज़ों में बताना चाहिए कि ये फ़ील्ड स्ट्रिंग हैं?
हाँ। स्ट्रिंग में सीरियलाइज़ करना सबसे सरल और टिकाऊ समाधान है, लेकिन यह तभी काम करता है जब उपभोक्ता मान को टेक्स्ट मानें, इसलिए फ़ील्ड टाइप API कॉन्ट्रैक्ट में लिखा होना चाहिए।