BSON Data Types & ObjectId
MongoDB documents look like JSON, but JSON only knows strings, numbers, booleans, null, arrays and objects. A database needs more than that: real dates, whole numbers that never lose precision, exact decimals for money and compact unique IDs. So MongoDB stores documents in BSON (Binary JSON), a binary format with many more types.
In this lesson you will learn the BSON types you will use every day, see how mongosh decides which number type to store, avoid the classic money and time-zone mistakes, and look inside an ObjectId.
The common BSON types
Each BSON type has a name (an alias) that you use when you check types in queries. These are the ones you will meet most often:
| Type | Alias | Example in mongosh | Typical use |
|---|---|---|---|
| String | string | 'Pune' | Text, always UTF-8, so Hindi text and the ₹ sign work |
| 32-bit integer | int | 250 | Counts, quantities, stock |
| 64-bit integer | long | Long('5000000000') | Very large whole numbers |
| Double | double | 4.5 | Measurements, ratings |
| Decimal128 | decimal | Decimal128('149.50') | Money and other exact decimals |
| Boolean | bool | true | Yes/no flags |
| Date | date | new Date() or ISODate('2026-10-30') | Points in time |
| ObjectId | objectId | ObjectId() | Default _id values |
| Array | array | ['tea', 'spices'] | Lists |
| Object | object | { city: 'Kochi' } | Embedded documents |
| Null | null | null | A known "no value" |
There are a few more, such as binary data (binData), regular expressions (regex) and internal timestamps (timestamp), but the list above covers almost every application.
One document, many types
Create a test document that uses most of these types. The comments after // are allowed in mongosh, because it is JavaScript:
use practice
db.typesdemo.insertOne({
_id: 1,
name: 'Masala Chai Mix', // string
qty: 250, // stored as int
rating: 4.5, // stored as double
weight: 1.0, // careful: stored as int
views: Long('5000000000'), // long
price: Decimal128('149.50'), // decimal
inStock: true, // bool
addedOn: new Date('2026-10-30T09:30:00+05:30'), // date: 9:30 am IST
tags: ['tea', 'spices'], // array
supplier: { name: 'Kochi Spices', city: 'Kochi' }, // object
discount: null // null
})
db.typesdemo.findOne(){ acknowledged: true, insertedId: 1 }
{
_id: 1,
name: 'Masala Chai Mix',
qty: 250,
rating: 4.5,
weight: 1,
views: Long('5000000000'),
price: Decimal128('149.50'),
inStock: true,
addedOn: ISODate('2026-10-30T04:00:00.000Z'),
tags: [ 'tea', 'spices' ],
supplier: { name: 'Kochi Spices', city: 'Kochi' },
discount: null
}Two things in the output deserve attention: weight printed as 1, and the date moved from 09:30 to 04:00. Both are explained below.
To see the stored type of each field, you can ask the server with the $type expression. You will learn aggregate() properly in The Aggregation Pipeline; here it is just a tool:
db.typesdemo.aggregate([
{ $project: { _id: 0, qty: { $type: '$qty' }, rating: { $type: '$rating' }, weight: { $type: '$weight' },
views: { $type: '$views' }, price: { $type: '$price' }, addedOn: { $type: '$addedOn' } } }
])[
{
qty: 'int',
rating: 'double',
weight: 'int',
views: 'long',
price: 'decimal',
addedOn: 'date'
}
]How mongosh chooses a number type
JavaScript has only one number type, so mongosh follows a simple rule: if a number is a whole number that fits in 32 bits (between about -2.1 billion and 2.1 billion), it is stored as an int; otherwise it is stored as a double. Since 1.0 and 1 are the same JavaScript number, weight: 1.0 became an int. If the type matters, say so explicitly with Double(1.0), Int32(250), Long('...') or Decimal128('...'). Pass large longs and decimals as strings, so JavaScript never rounds them first.
Numbers of different types still compare by value, so a query for { weight: 1 } matches an int 1, a double 1.0 and a long 1 alike. Problems appear only when code checks the type itself, or when a value is stored as a string.
Money: never use doubles
Doubles are binary fractions, and most decimal amounts cannot be stored exactly in them. You can see the effect in mongosh itself:
0.1 + 0.20.30000000000000004
That tiny error turns into wrong totals and failed comparisons once you add up thousands of payments. For money, use one of two safe designs:
- Store Decimal128 values, which keep exact decimal digits:
Decimal128('149.50'). - Store whole paise as integers: ₹149.50 becomes
14950, and you divide by 100 only for display.
The practice shop in this course stores whole rupees as integers (price: 799), which is exact and keeps outputs simple.
Dates are stored in UTC
A BSON date is a count of milliseconds since 1 January 1970, always in UTC (Coordinated Universal Time). When you created the date with +05:30, the Indian time offset, MongoDB converted 09:30 IST into 04:00 UTC. mongosh prints dates with ISODate(...) and a Z at the end, which means UTC. Your application converts back to IST only when it shows the date to a person.
Use new Date() or ISODate() to create date values. Do not use Date() without new: in JavaScript that returns a string, and a date stored as a string cannot be compared or sorted as a date.
Inside an ObjectId
An ObjectId is 12 bytes, shown as 24 hexadecimal characters. The first 4 bytes are the creation time in seconds, the next 5 bytes are a random value chosen once per process, and the last 3 bytes are a counter. This makes ObjectIds unique without asking the server, and roughly sorted by creation time. You can read the time back:
const id = ObjectId('6ae41d48c3f5e8a91d2b7a01')
id.getTimestamp()
id.toString()ISODate('2026-10-30T04:30:00.000Z')
6ae41d48c3f5e8a91d2b7a01getTimestamp() returns the creation time and toString() returns the plain hex string, which is what you would put in a URL such as /orders/6ae41d48c3f5e8a91d2b7a01. Calling ObjectId() with no argument creates a brand-new one.
Common mistakes
- Storing numbers as strings.
price: '799'is text, so{ price: 799 }will not match it and sorting puts'1299'before'799'. Store numbers as numbers. - Using doubles for money. Use Decimal128 or integer paise.
- Storing dates as text.
'30-10-2026'cannot be compared with other dates. Use real date values. - Expecting dates in local time. MongoDB returns UTC; convert for display.
Key points
- MongoDB stores documents as BSON, which adds types such as int, long, double, decimal, date and ObjectId to JSON.
mongoshstores whole numbers that fit in 32 bits asintand everything else asdouble, so1.0becomes an int.- Use
Decimal128or integer paise for money, never doubles. - Dates are stored in UTC;
new Date()andISODate()create them,Date()returns a string. - An ObjectId holds a timestamp, a random value and a counter;
getTimestamp()reads the time.
Exercise
In the practice database, insert a document into a payments collection for a UPI payment of ₹1,299.50 made by Priya at 6:45 pm IST on 2 November 2026. Store the amount exactly, store the time as a real date, and let MongoDB create the _id. Then read the document back and work out the UTC time you expect to see.
Show solution
db.payments.insertOne({
customer: 'Priya Nair',
method: 'UPI',
amount: Decimal128('1299.50'),
paidAt: new Date('2026-11-02T18:45:00+05:30')
})
db.payments.findOne()The amount prints as Decimal128('1299.50') and the date as ISODate('2026-11-02T13:15:00.000Z'), because 6:45 pm IST is 5 hours 30 minutes ahead of UTC. The _id is a new ObjectId whose timestamp is the moment you ran the insert.
Quick Quiz
1. In mongosh, which type is stored for { weight: 1.0 }?
1.0 and 1 are the same JavaScript number, and whole numbers that fit in 32 bits are stored as int.
2. Which type should you use for prices with paise, such as ₹149.50?
Decimal128 stores decimal digits exactly; doubles cannot represent most decimal amounts exactly.
3. A document has createdAt: ISODate('2026-10-30T04:00:00.000Z'). What is that in IST?
IST is UTC plus 5 hours 30 minutes, so 04:00 UTC is 09:30 IST.
4. What do the first 4 bytes of an ObjectId contain?
The leading 4 bytes are a timestamp, which getTimestamp() reads back.
Learn MongoDB with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
