MongoD...aTypes(3pm)

๐Ÿ“ฆ
version 2.2.2 ยท 5 versions
, in debian trixie, ubuntu resolute, ubuntu stonking

๐Ÿ’– MongoDB::DataTypes ๐Ÿ’–

okay bestie, gather round, because this is the page that explains how the MongoDB Perl driver (that's MongoDB::DataTypes, from User Contributed Perl Documentation) handles BSON data types. it's long. it's important. it's giving โœจreference materialโœจ and we're gonna get through it together.


๐ŸŒธ NAME ๐ŸŒธ

MongoDB::DataTypes โ€” using MongoDB data types with Perl. that's it, that's the whole vibe. ๐Ÿซถ


โญ VERSION โญ

version v2.2.2


๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

so MongoDB stores typed data in a data format called BSON (http://bsonspec.org/). and THIS document is the one that tells you how to work with all those BSON data types when you're writing Perl against the MongoDB Perl driver. slay.

and here's the plot twist: as of MongoDB Perl driver v2.0.0, the driver doesn't even do the conversion itself anymore. it relies on the external BSON library (plus the optional BSON::XS library) to convert between your Perl data and the MongoDB BSON format. iconic delegation, honestly. ๐Ÿ’…

โœจ Additional information โœจ

want more tea? there's more tea. these MongoDB manual pages have extra info about MongoDB documents and types:


๐Ÿ‘‘ ESSENTIAL CONCEPTS ๐Ÿ‘‘

๐Ÿ’œ MongoDB records are ordered documents

a MongoDB record (like, a "row", if you're coming from SQL-land) is a BSON document โ€” which is a list of key-value pairs. sounds like a Perl hash, right? WRONG, bestie. it's a hash's more organized cousin, because the keys in a BSON document are ordered. keys are always strings. values can be any of 20+ BSON types. twenty plus. the range. ๐ŸŒˆ

oh and also โ€” queries and update specifications? those are documents too. everything's a document. it's documents all the way down. ๐Ÿซ 

๐ŸŽ€ Type wrapper classes provide non-native and disambiguated types

some BSON types just don't exist natively in Perl, so we wrap them in type wrapper classes from the BSON library, like BSON::OID and BSON::Time. little outfits for your data. adorable.

and even when a type IS native, you sometimes still need a wrapper to work around the limits of Perl's type system. for example, you can use BSON::Doc when you need an ordered hash, or BSON::Int64 when you need a 64-bit integer.

the BSON class has attributes that configure how type wrappers get used during encoding and decoding, so you can tune the whole situation to your liking.

and if you want the FULL table of every single BSON type conversion? that lives in the PERL-BSON Type Mapping documentation. go check it out, it's thorough fr fr.

๐Ÿงš String/number type conversion heuristics

okay this part is lowkey the most important part for not losing your mind. Perl scalar values can have several underlying, internal representations โ€” like double, integer, or string (see perlguts for the deep lore). and when the driver encodes to BSON, the default behavior goes like this:

  • if the value has a valid double representation, it gets encoded to BSON as a double.
  • otherwise, if the value has a valid integer interpretation, it gets encoded as either Int32 or Int64 โ€” whichever is the smallest type the value fits into. and if the value overflows? it errors. no silent nonsense here.
  • and otherwise? it gets encoded as a UTF-8 string.

but wait, there's more ๐Ÿ’… โ€” the BSON library gives you the prefer_numeric attribute if you want to more aggressively coerce number-like strings that don't already have a numeric representation into a numeric form. aggressive. love that for you.

๐Ÿ’€ Order sometimes matters a lot

here's the rule, and honestly it's the one that ruins people's whole day if they miss it:

when you're writing a query document, the order of the top level keys doesn't matter. but the order of keys in any embedded documents absolutely does.

$coll->insert_one({
    name => { first => "John", last => "Doe" },
    age => 42,
    color => "blue",
});

# Order doesn't matter here
$coll->find( { age => 42, color => "blue" } );     # MATCH
$coll->find( { color => "blue", age => 42 } );     # MATCH

# Order *does* matter here
$coll->find(
    { name => { first => "John", last => "Doe" } } # MATCH
);
$coll->find(
    { name => { last => "Doe", first => "John" } } # NO MATCH
);

see that last one? # NO MATCH. just because you swapped two keys inside a nested doc. that's the whole game. ๐Ÿ™ˆ

and when you're specifying a sort order or the order of keys for an index, order matters any time there's more than one key. periodt.

okay and here's the scary one: because of Perl's hash order randomization, be very careful using native hashes with MongoDB. this is a real footgun, not a cute one. hit up the "Documents" section below for specific guidance.

๐Ÿ“ THE BSON::TYPES LIBRARY ๐Ÿ“

BSON::Types is a library full of helper subroutines that make creating BSON type wrappers super easy. and using it is highly recommended. do it. do it right now.

use BSON::Types ':all';

$int64   = bson_int64(42);         # force encoding more bits
$decimal = bson_decimal("24.01");  # Decimal128 type
$time    = bson_time();            # now

and heads up for everything else in this document: all the examples from here on assume that all the BSON::Types helper functions are loaded. so just assume they're in the room with us. ๐Ÿซถ


๐Ÿ‘‘ NOTES ON SPECIFIC TYPES ๐Ÿ‘‘

okay bestie, this is the part where we go type by type and I tell you all the little gossip about each one. buckle up. ๐Ÿ’–


๐ŸŒˆ Arrays

BSON arrays encode and decode via Perl array references. that's it, that's the whole vibe. [] in, [] out. slay.

๐Ÿ“„ Documents

so here's the tea: Perl's hashes guarantee key-order randomness, so if you use a hash reference as a document, you're gonna get a BSON document with a different key order. ๐Ÿ™ˆ

For the top-level keys, this usually shouldn't cause problems, but it can cause problems for embedded documents when you're querying, sorting or indexing on the embedded document. mess.

For sending data to the server, the BSON::Doc class provides a very lightweight wrapper around ordered key-value pairs, but it's opaque.

$doc = bson_doc( name => "Larry", color => "purple" );

You can also use Tie::IxHash for a more-interactive ordered document, but at the expense of tied-object overhead.

The BSON encoder has an ordered attribute that, if enabled, returns all documents as order-preserving tied hashes. This is slow, but is the only way to ensure that documents can roundtrip preserving key order.

๐Ÿ”ข Numbers

By default, the BSON decoder decodes doubles and integers into a Perl-native form. To maximize fidelity during a roundtrip, the decoder supports the wrap_numbers attribute to always decode to a BSON type wrapper class with numeric overloading.

๐Ÿงฎ 32-bit Platforms

On a 32-bit platform, the BSON library treats Math::BigInt as the "native" type for integers outside the (signed) 32-bit range. Values that are encoded as 64-bit integers will be decoded as Math::BigInt objects.

๐Ÿ’ช 64-bit Platforms

On a 64-bit platform, (signed) Int64 values are supported, but, by default, numbers will be stored in the smallest BSON size needed. To force a 64-bit representation for numbers in the signed 32-bit range, use a type wrapper:

$int64 = bson_int64(0); # 64 bits of 0

๐ŸŒŠ Long doubles

On a perl compiled with long-double support, floating point number precision will be lost when sending data to MongoDB. ๐Ÿ˜ญ tragic, I know.

๐Ÿ’ฐ Decimal128

MongoDB 3.4 adds support for the IEEE 754 Decimal128 type. The BSON::Decimal128 class is used as a proxy for these values for both inserting and querying documents. Be sure to use strings when constructing Decimal128 objects.

$item = {
    name => "widget",
    price => bson_decimal128("4.99"), # 4.99 as a string
    currency => "USD",
};

$coll->insert_one($item);

๐ŸŽ€ Strings

String values are expected to be character-data (not bytes). They are encoded as UTF-8 before being sent to the database and decoded from UTF-8 when received. If a string can't be decoded, an error will be thrown. ๐Ÿšจ

To save or query arbitrary, non-UTF8 bytes, use a binary type wrapper (see "Binary Data", below).

โœ… Booleans

Boolean values are emulated using the boolean package via the boolean::true and boolean::false functions. Using boolean objects in documents will ensure the documents have the BSON boolean type in the database. Likewise, BSON boolean types in the database will be returned as boolean objects.

An example of inserting boolean values:

use boolean;

$collection->insert_one({"okay" => true, "name" => "fred"});

An example of using boolean values for query operators (only returns documents where the name field exists):

$cursor = $collection->find({"name" => {'$exists' => true}});

Often, you can just use 1 or 0 in query operations instead of "true" and "false", but some commands require boolean objects and the database will return an error if integers 1 or 0 are used. no cap.

Boolean objects from the following JSON libraries will also be encoded correctly in the database:

  • JSON::XS
  • JSON::PP
  • Cpanel::JSON::XS
  • Mojo::JSON
  • JSON::Tiny

๐Ÿ†” Object IDs

The BSON object ID type (aka "OID") is a 12 byte identifier that ensures uniqueness by mixing a timestamp and counter with host and process-specific bytes. iconic behavior honestly.

All MongoDB documents have an "_id" field as a unique identifier. This field does not have to be an object ID, but if the field does not exist, an object ID is created automatically for it when the document is inserted into the database. โœจ

The BSON::OID class is the type wrapper for object IDs.

To create a unique id:

$oid = bson_oid();

To create a BSON::OID from an existing 24-character hexadecimal string:

$oid = bson_oid("123456789012345678901234");

๐Ÿ” Regular Expressions

Use "qr/.../" to use a regular expression in a query, but be sure to limit your regular expression to syntax and features supported by PCRE, which are not fully compatible with Perl <https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions#Differences_from_Perl>. ๐Ÿ’…

$cursor = $collection->find({"name" => qr/[Jj]oh?n/});

Regular expressions will match strings saved in the database.

NOTE: only the following flags are supported: "imsxlu".

You can also save and retrieve regular expressions themselves, but regular expressions will be retrieved as BSON::Regex objects for safety (these will round-trip correctly).

From that object, you can attempt to compile a reference to a "qr{}" using the "try_compile" method. However, due to PCRE differences, this could fail to compile or could have different match behavior than intended. ๐Ÿ™ˆ

$collection->insert_one({"regex" => qr/foo/i});
$obj = $collection->find_one;
if ("FOO" =~ $obj->{regex}->try_compile) { # matches
    print "hooray\n";
}
๐Ÿšจ SECURITY NOTE ๐Ÿšจ: A regular expression can evaluate arbitrary code if "use re 'eval'" is in scope. You are strongly advised never to use untrusted input as a regular expression. bestie please. for real. do not do this. ๐Ÿ’€

๐Ÿ“… Dates

BSON has a datetime type representing signed Int64 milliseconds relative to the Unix epoch. As of MongoDB v2.0.0, the lightweight BSON::Time wrapper is now the default wrapper for datetime data.

The bson_time() helper function uses fractional epoch seconds, for better integration with the Time::HiRes module:

use Time::HiRes 'time';

$later = bson_time( time() + 60 );

For convenience, The default value for the helper is "Time::HiRes::time":

$now = bson_time();

BSON::Time has methods for inflating into various popular Perl date classes, including DateTime, Time::Moment and DateTime::Tiny. The BSON encoder can also encode objects of these types, with limitations on precision and timezone based on the underlying class. For example, DateTime::Tiny has no time zone or sub-second precision. ๐Ÿ•ฐ๏ธ

๐Ÿ–ผ๏ธ Binary Data

By default, all database strings are UTF-8. To store images, binaries, and other non-UTF-8 data, one can use the BSON binary data type via the BSON::Bytes wrapper.

The BSON binary type includes the notion of a "subtype" attribute, which can be any integer between 0 and 255. The meaning of subtypes from 0 to 127 are reserved for definition by MongoDB; values 128 to 255 are user-defined. Binary data values will only match in a MongoDB query if both the binary bytes and the subtypes are the same. The default subtype is 0 (a.k.a. "generic binary data") and generally should not be modified.

To roundtrip binary data, use the BSON::Bytes wrapper:

# non-utf8 string
$bytes = "\xFF\xFE\xFF";

$collection->insert_one({"photo" => bson_bytes($bytes)});

Binary data will be decoded into a BSON::Bytes object. It stringifies as the underlying bytes for convenience. ๐Ÿซถ

One can also store binary data by using a string reference.

$collection->insert_one({"photo" => \$bytes});

โฌ‡๏ธโฌ†๏ธ MinKey and MaxKey

BSON::MinKey is "less than" any other value of any type. This can be useful for always returning certain documents first.

BSON::MaxKey is "greater than" any other value of any type. This can be useful for always returning certain documents last.

There is a helper function for each:

$min = bson_minkey();
$max = bson_maxkey();

๐Ÿ’œ AUTHORS ๐Ÿ’œ

  • David Golden <david@mongodb.com>
  • Rassi <rassi@mongodb.com>
  • Mike Friedman <friedo@friedo.com>
  • Kristina Chodorow <k.chodorow@gmail.com>
  • Florian Ragwitz <rafl@debian.org>

This software is Copyright (c) 2020 by MongoDB, Inc.

This is free software, licensed under:

The Apache License, Version 2.0, January 2004

and that's the whole page bestie!! โœจ this was MongoD...aTypes(3pm) from perl v5.40.1, dated 2025-04-03, made with so much love by the MongoDB crew ๐Ÿซถ๐Ÿ’– go forth and encode responsibly, mwah ๐Ÿ’…๐ŸŒธ

๐Ÿ“ฆ where this page comes from