or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

data-types.mdexperimental.mdextended-json.mdindex.mdserialization.mdutilities.md
tile.json

extended-json.mddocs/

Extended JSON (EJSON)

Extended JSON functionality for converting BSON data to/from human-readable JSON format while preserving type information and ensuring round-trip fidelity.

Capabilities

EJSON Parse

Parse Extended JSON string to JavaScript/BSON objects with type preservation.

/**
 * Parse Extended JSON string to JavaScript/BSON objects
 * @param text - Extended JSON string to parse
 * @param options - Optional parsing configuration
 * @returns Parsed JavaScript object with BSON types
 */
function parse(text: string, options?: EJSONOptions): any;

interface EJSONOptions {
  /** Output using Extended JSON v1 spec (default: false) */
  legacy?: boolean;
  /** Return native JS types when possible rather than BSON types (default: true) */
  relaxed?: boolean;
  /** Use native BigInt for 64-bit integers (default: false) */
  useBigInt64?: boolean;
}

Usage Examples:

import { EJSON } from "bson";

// Parse with BSON types preserved
const ejsonString = '{ "id": { "$oid": "507f1f77bcf86cd799439011" }, "count": { "$numberLong": "42" } }';
const strict = EJSON.parse(ejsonString, { relaxed: false });
console.log(strict.id); // ObjectId instance
console.log(strict.count); // Long instance

// Parse with relaxed mode (native JS types when possible)
const relaxed = EJSON.parse(ejsonString, { relaxed: true });
console.log(relaxed.id); // ObjectId instance (can't convert to string)
console.log(relaxed.count); // 42 (converted to number)

// Parse with BigInt support
const bigIntString = '{ "bigValue": { "$numberLong": "9223372036854775807" } }';
const withBigInt = EJSON.parse(bigIntString, { useBigInt64: true });
console.log(typeof withBigInt.bigValue); // "bigint"

EJSON Stringify

Convert JavaScript/BSON objects to Extended JSON string format.

/**
 * Convert JavaScript/BSON objects to Extended JSON string
 * @param value - Object to convert to Extended JSON
 * @param replacer - Function or array to transform values (like JSON.stringify)
 * @param space - Indentation for pretty-printing (like JSON.stringify)
 * @param options - Optional stringification configuration
 * @returns Extended JSON string representation
 */
function stringify(
  value: any,
  replacer?: Function | Array,
  space?: string | number,
  options?: EJSONOptions
): string;

Usage Examples:

import { EJSON, ObjectId, Long } from "bson";

const document = {
  _id: new ObjectId(),
  count: Long.fromNumber(42),
  timestamp: new Date(),
  binary: new Uint8Array([1, 2, 3, 4])
};

// Strict Extended JSON with type preservation
const strict = EJSON.stringify(document, undefined, 2, { relaxed: false });
console.log(strict);
// {
//   "_id": { "$oid": "..." },
//   "count": { "$numberLong": "42" },
//   "timestamp": { "$date": "2023-..." },
//   "binary": { "$binary": { "base64": "AQIDBA==", "subType": "00" } }
// }

// Relaxed Extended JSON (more readable)
const relaxed = EJSON.stringify(document, undefined, 2, { relaxed: true });
console.log(relaxed);
// {
//   "_id": { "$oid": "..." },
//   "count": 42,
//   "timestamp": "2023-...",
//   "binary": { "$binary": { "base64": "AQIDBA==", "subType": "00" } }
// }

// With custom replacer function
const filtered = EJSON.stringify(document, (key, value) => {
  if (key === 'binary') return undefined; // Exclude binary data
  return value;
});

EJSON Serialize

Serialize BSON objects to Extended JSON object representation (not string).

/**
 * Serialize BSON objects to Extended JSON object representation
 * @param bson - BSON object to serialize
 * @param options - Optional serialization configuration
 * @returns Extended JSON object (not string)
 */
function serialize(bson: any, options?: EJSONOptions): any;

Usage Examples:

import { EJSON, ObjectId, Decimal128 } from "bson";

const bsonDoc = {
  _id: new ObjectId(),
  price: Decimal128.fromString("19.99"),
  active: true
};

// Serialize to Extended JSON object
const ejsonObj = EJSON.serialize(bsonDoc, { relaxed: false });
console.log(ejsonObj);
// {
//   _id: { $oid: "..." },
//   price: { $numberDecimal: "19.99" },
//   active: true
// }

// Can be used with regular JSON.stringify for final string conversion
const jsonString = JSON.stringify(ejsonObj, null, 2);

EJSON Deserialize

Deserialize Extended JSON object back to JavaScript/BSON objects.

/**
 * Deserialize Extended JSON object to JavaScript/BSON objects
 * @param ejson - Extended JSON object to deserialize
 * @param options - Optional deserialization configuration
 * @returns JavaScript object with BSON types
 */
function deserialize(ejson: any, options?: EJSONOptions): any;

Usage Examples:

import { EJSON } from "bson";

// Extended JSON object (not string)
const ejsonObj = {
  _id: { $oid: "507f1f77bcf86cd799439011" },
  count: { $numberLong: "42" },
  price: { $numberDecimal: "19.99" },
  timestamp: { $date: "2023-10-15T10:30:00.000Z" }
};

// Deserialize to BSON objects
const bsonDoc = EJSON.deserialize(ejsonObj, { relaxed: false });
console.log(bsonDoc._id); // ObjectId instance
console.log(bsonDoc.count); // Long instance
console.log(bsonDoc.price); // Decimal128 instance
console.log(bsonDoc.timestamp); // Date instance

// Deserialize with relaxed mode
const relaxedDoc = EJSON.deserialize(ejsonObj, { relaxed: true });
console.log(typeof relaxedDoc.count); // "number" (if within safe range)

Extended JSON Format Specification

Extended JSON provides a way to represent BSON types in JSON format. There are two modes:

Strict Mode (relaxed: false)

All BSON types are explicitly marked with $type indicators:

{
  "_id": { "$oid": "507f1f77bcf86cd799439011" },
  "count": { "$numberLong": "42" },
  "price": { "$numberDecimal": "19.99" },
  "timestamp": { "$date": "2023-10-15T10:30:00.000Z" },
  "binary": { "$binary": { "base64": "AQIDBA==", "subType": "00" } },
  "regex": { "$regularExpression": { "pattern": "^test", "options": "i" } }
}

Relaxed Mode (relaxed: true)

Native JSON types are used when possible for better readability:

{
  "_id": { "$oid": "507f1f77bcf86cd799439011" },
  "count": 42,
  "price": { "$numberDecimal": "19.99" },
  "timestamp": "2023-10-15T10:30:00.000Z",
  "binary": { "$binary": { "base64": "AQIDBA==", "subType": "00" } },
  "regex": "/^test/i"
}

Type Mappings

BSON to Extended JSON

// ObjectId
new ObjectId() → { "$oid": "507f1f77bcf86cd799439011" }

// Long (strict mode)
Long.fromNumber(42) → { "$numberLong": "42" }

// Long (relaxed mode, when safe)
Long.fromNumber(42) → 42

// Decimal128
Decimal128.fromString("19.99") → { "$numberDecimal": "19.99" }

// Binary
new Binary([1,2,3,4]) → { "$binary": { "base64": "AQIDBA==", "subType": "00" } }

// Date (strict mode)
new Date() → { "$date": "2023-10-15T10:30:00.000Z" }

// Date (relaxed mode)
new Date() → "2023-10-15T10:30:00.000Z"

// RegExp (strict mode)
/pattern/flags → { "$regularExpression": { "pattern": "pattern", "options": "flags" } }

// RegExp (relaxed mode)
/pattern/flags → "/pattern/flags"

// Timestamp
new Timestamp(1, 1697365800) → { "$timestamp": { "t": 1697365800, "i": 1 } }

// MinKey/MaxKey
new MinKey() → { "$minKey": 1 }
new MaxKey() → { "$maxKey": 1 }

Round-Trip Fidelity

Extended JSON ensures perfect round-trip conversion:

import { EJSON, serialize, deserialize } from "bson";

const original = {
  _id: new ObjectId(),
  bigNumber: Long.fromString("9223372036854775807"),
  precise: Decimal128.fromString("123.456789012345678901234567890")
};

// BSON → Extended JSON → BSON
const ejsonString = EJSON.stringify(original, undefined, undefined, { relaxed: false });
const restored = EJSON.parse(ejsonString, { relaxed: false });

// Should be identical to original
console.log(original._id.equals(restored._id)); // true
console.log(original.bigNumber.equals(restored.bigNumber)); // true
console.log(original.precise.toString() === restored.precise.toString()); // true

// Also works with binary serialization
const bsonBytes = serialize(original);
const fromBson = deserialize(bsonBytes);
const ejsonFromBson = EJSON.stringify(fromBson, undefined, undefined, { relaxed: false });
const backToBson = EJSON.parse(ejsonFromBson, { relaxed: false });

// Perfect round-trip fidelity
console.log(original._id.equals(backToBson._id)); // true

Legacy Format Support

Extended JSON v1 format is supported for backwards compatibility:

import { EJSON } from "bson";

const document = { count: Long.fromNumber(42) };

// Extended JSON v2 (default)
const v2 = EJSON.stringify(document);
// { "count": { "$numberLong": "42" } }

// Extended JSON v1 (legacy)
const v1 = EJSON.stringify(document, undefined, undefined, { legacy: true });
// { "count": { "$numberLong": 42 } } // Note: number instead of string