BSON
Library
BSON
Overview
BSON (Binary JSON) is a binary-encoded format of JSON, developed as the primary data storage and transfer format for MongoDB. While maintaining the convenience of JSON, it provides fast parsing and traversal through binary format, and supports extended data types (dates, binary data, ObjectId, etc.). In JavaScript/TypeScript environments, it is integrated with MongoDB drivers and used transparently in database operations.
Details
BSON was designed to extend JSON's expressiveness while achieving efficient data storage and processing. By including length information for each element, it allows access to specific elements without parsing the entire data. MongoDB internally stores all documents in BSON format, optimizing index creation and query processing. It natively supports types that cannot be represented in standard JSON, such as dates, regular expressions, and binary data, supporting practical application development.
Key Features
- Extended data types: Supports over 12 types including ObjectId, Date, Binary, Decimal128
- Efficient traversal: Fast data access through length prefixes
- MongoDB integration: Full support as MongoDB's standard data format
- Language neutrality: Official drivers for multiple languages
- Schema-less: Flexible data structure similar to JSON
- Binary safe: Direct storage of binary data possible
Advantages and Disadvantages
Advantages
- Native support for extended types like dates and binary data
- Faster parsing and serialization than JSON
- Seamless integration with MongoDB
- Distributed system support with unique ObjectId generation
- Efficient querying of nested structures
- Preserves type information during storage and retrieval
Disadvantages
- Tends to be larger in file size than JSON
- Binary format not human-readable
- Limited adoption outside MongoDB
- Difficult to edit and debug in text editors
- Higher learning curve than JSON
- Limited support in some programming languages
References
Code Examples
Basic Usage
// Import BSON library
import { BSON, ObjectId } from 'bson';
// Create BSON document
const document = {
_id: new ObjectId(),
name: 'John Doe',
age: 30,
createdAt: new Date(),
isActive: true,
scores: [85, 90, 78],
profile: {
bio: 'Software Engineer',
avatar: Buffer.from('binary data')
}
};
// Serialize to BSON
const bsonData = BSON.serialize(document);
console.log('BSON size:', bsonData.length, 'bytes');
// Deserialize from BSON
const parsedDoc = BSON.deserialize(bsonData);
console.log('Parsed:', parsedDoc);
Using Extended JSON (EJSON)
import { EJSON } from 'bson';
// Document with extended types
const doc = {
_id: new ObjectId(),
price: BSON.Decimal128.fromString('99.99'),
pattern: /^test$/i,
binary: new BSON.Binary(Buffer.from('hello')),
timestamp: new Date()
};
// Convert to EJSON (express extended types in string format)
const ejsonString = EJSON.stringify(doc, { relaxed: false });
console.log('EJSON:', ejsonString);
// Restore from EJSON
const restored = EJSON.parse(ejsonString);
console.log('Restored types:', {
isObjectId: restored._id instanceof ObjectId,
isDecimal: restored.price instanceof BSON.Decimal128,
isRegExp: restored.pattern instanceof RegExp
});
MongoDB Integration
import { MongoClient, ObjectId } from 'mongodb';
async function mongoExample() {
const client = new MongoClient('mongodb://localhost:27017');
await client.connect();
const db = client.db('myapp');
const users = db.collection('users');
// Insert document using BSON types
const result = await users.insertOne({
_id: new ObjectId(),
name: 'Jane Smith',
birthDate: new Date('1990-05-15'),
tags: ['developer', 'tokyo'],
metadata: new BSON.Binary(Buffer.from('metadata')),
lastLogin: new Date()
});
// Query using ObjectId
const user = await users.findOne({
_id: new ObjectId(result.insertedId)
});
// Range query using date type
const recentUsers = await users.find({
lastLogin: { $gte: new Date(Date.now() - 24*60*60*1000) }
}).toArray();
await client.close();
}
Custom Type Handling
import { BSON } from 'bson';
// Custom class
class Location {
constructor(lat, lng) {
this.latitude = lat;
this.longitude = lng;
}
toBSON() {
return {
type: 'Point',
coordinates: [this.longitude, this.latitude]
};
}
static fromBSON(doc) {
if (doc.type === 'Point') {
return new Location(doc.coordinates[1], doc.coordinates[0]);
}
return doc;
}
}
// Usage
const location = new Location(35.6762, 139.6503); // Tokyo
const bson = BSON.serialize({ location });
const parsed = BSON.deserialize(bson);
console.log('Location:', parsed.location);
Type-safe Usage with TypeScript
import { ObjectId, Decimal128 } from 'bson';
// Type definition
interface Product {
_id: ObjectId;
name: string;
price: Decimal128;
categories: string[];
inStock: boolean;
createdAt: Date;
image?: Buffer;
}
// Type-safe BSON operations
function createProduct(data: Omit<Product, '_id'>): Product {
return {
_id: new ObjectId(),
...data
};
}
const product = createProduct({
name: 'TypeScript Guide',
price: Decimal128.fromString('29.99'),
categories: ['Books', 'Programming'],
inStock: true,
createdAt: new Date()
});
// Serialize/Deserialize
const bsonData = BSON.serialize(product);
const restored = BSON.deserialize(bsonData) as Product;
// Type checking is effective
console.log(restored.price.toString()); // "29.99"
Binary Data Processing
import { BSON } from 'bson';
import fs from 'fs';
// Save image file
async function saveImageToBSON(imagePath, outputPath) {
const imageBuffer = await fs.promises.readFile(imagePath);
const document = {
filename: imagePath.split('/').pop(),
contentType: 'image/jpeg',
data: new BSON.Binary(imageBuffer),
uploadedAt: new Date(),
size: imageBuffer.length
};
const bsonData = BSON.serialize(document);
await fs.promises.writeFile(outputPath, bsonData);
return bsonData.length;
}
// Restore image
async function loadImageFromBSON(bsonPath) {
const bsonData = await fs.promises.readFile(bsonPath);
const document = BSON.deserialize(bsonData);
// Get binary data as Buffer
const imageBuffer = document.data.buffer;
return {
filename: document.filename,
contentType: document.contentType,
data: imageBuffer,
size: document.size
};
}