
=pod

=head1 NAME

MongoDB::DataTypes - The data types used with MongoDB

=head1 DESCRIPTION

This goes over the types you can save to the database and use for queries.

=head1 TYPES

=head2 Strings

All strings must be valid UTF-8 to be sent to the database.  If a string is not
valid, it will not be saved.  If you need to save a non-UTF-8 string, you can 
save it as a binary blob (see the Binary Data section below).  

All strings returned from the database have the UTF-8 flag set.

Unfortunately, due to Perl weirdness, UTF-8 is not very pretty.  For example,
suppose we have a UTF-8 string:

    my $str = 'Åland Islands';

Now, let's print it:

    print "$str\n";

You can see in the output:

    "\x{c5}land Islands"

Lovely, isn't it?  This is how Perl prints UTF-8.  To make it "pretty," there
are a couple options:

    my $pretty_str = utf8::encode($str);

This, unintuitively, clears the UTF-8 flag.  

You can also just run

    binmode STDOUT, ':utf8';

and then the string (and all future UTF-8 strings) will print "correctly."

=head2 Dates

The L<DateTime> package can be used insert and query for dates. Dates stored in 
the database will be returned as instances of DateTime.

An example of storing and retrieving a date:

    use DateTime;

    my $now = DateTime->now;
    $collection->insert({'ts' => $now});

    my $obj = $collection->find_one;
    print "Today is ".$obj->{'ts'}->ymd."\n";

An example of querying for a range of dates:

    my $start = DateTime->from_epoch( epoch => 100000 );
    my $end = DateTime->from_epoch( epoch => 500000 );

    my $cursor = $collection->query({event => {'$gt' => $start, '$lt' => $end}});

B<Warning: creating L<DateTime> objects is extremely slow.  Consider saving 
dates as numbers and converting the numbers to L<DateTime>s when needed.  A single
L<DateTime> field can make deserialization up to 10 times slower.>

=head2 Regular Expressions

Use C<qr/.../> to use a regular expression in a query:

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

Regular expressions will match strings saved in the database.

You can also save and retrieve regular expressions themselves:

    $collection->insert({"regex" => qr/foo/i});
    $obj = $collection->find_one;
    if ("FOO" =~ $obj->{'regex'}) { # matches
        print "hooray\n";
    }

Note for Perl 5.8 users: flags are lost when regular expressions are retrieved 
from the database (this does not affect queries or Perl 5.10+).

=head2 Booleans

Use the L<boolean> package to get boolean values.  C<boolean::true> and 
C<boolean::false> are the only parts of the package used, currently.

An example of inserting boolean values:

    use boolean;

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

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

    my $cursor = $collection->query({"name" => {'$exists' => boolean::true}});

Most of the time, you can just use 1 or 0 instead of C<true> and C<false>, such
as for specifying fields to return.  L<boolean> is the only way to save 
booleans to the database, though.

=head2 Numbers

By default, numbers with a decimal point will be saved as doubles (64-bit).

=head3 32-bit Platforms

Numbers without decimal points will be saved as 32-bit integers.  To save a 
number as a 64-bit integer, use bigint:

    use bigint;

    $collection->insert({"user_id" => 28347197234178})

The driver will die if you try to insert a number beyond the signed 64-bit 
range: -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807.

Numbers that are saved as 64-bit integers will be decoded as doubles.

=head3 64-bit Platforms

Numbers without a decimal point will be saved and returned as 64-bit integers.
Note that there is no way to save a 32-bit int on a 64-bit machine.  

Keep in mind that this can cause some weirdness to ensue if some machines are
32-bit and others are 64-bit.  Take the following example:

=over 4

=item * Programmer 1 saves an int on a 32-bit platform.

=item * Programmer 2 retrieves the document on a 64-bit platform and re-saves
it, effectively converting it to a 64-bit int.

=item * Programmer 1 retrieves the document on their 32-bit machine, which 
decodes the 64-bit int as a double.

=back

Nothing drastic, but good to be aware of.

=head4 64-bit integers in the shell

The Mongo shell has one numeric type: the 8-byte float.  This means that it 
cannot always represent an 8-byte integer exactly.  Thus, when you display a
64-bit integer in the shell, it will be wrapped in a subobject that indicates
it might be an approximate value.  For instance, if we run this Perl on a 
64-bit machine:

    $coll->insert({_id => 1});

then look at it in the shell, we see:

    > db.whatever.findOne()
    {
        "_id" : 
            {
                "floatApprox" : 1
            }
    }

This doesn't mean that we saved a float, it just means that the float value of 
a 64-bit integer may not be exact.

=head2 MongoDB::OID

"OID" stands for "Object ID", and is a unique id that is automatically added to 
documents if they do not already have an C<_id> field before they are saved to 
the database.  They are 12 bytes which are guarenteed to be unique.  Their 
string form is a 24-character string of hexidecimal digits.

To create a unique id:

    my $oid = MongoDB::OID->new;

To create a MongoDB::OID from an existing 24-character hexidecimal string:

    my $oid = MongoDB::OID->new("123456789012345678901234");

=head2 Binary Data

By default, all database strings are UTF8.  To save images, binaries, and other
non-UTF8 data, you can pass the string as a reference to the database.  For 
example:

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

    $collection->insert({"photo" => \$string});

This will save the variable as binary data, bypassing the UTF8 check.

Binary data can be matched exactly by the database, so this query will match 
the object we inserted above:

    $collection->find({"photo" => \$string});

Comparisons (e.g., $gt, $lt) may not work as you expect with binary data, so it
is worth experimenting.

=head2 MongoDB::Code

L<MongoDB::Code> is used to represent JavaScript code and, optionally, scope.
To create one:

    use MongoDB::Code;

    my $code = MongoDB::Code->new("code" => "function() { return 'hello, world'; }");

Or, with a scope:

    my $code = MongoDB::Code->new("code" => "function() { return 'hello, '+name; }",
        "scope" => {"name" => "Fred"});

Which would then return "hello, Fred" when run.

=head2 MongoDB::MinKey

C<MongoDB::MinKey> is "less than" any other value of any type.  This can be useful
for always returning certain documents first (or last).

C<MongoDB::MinKey> has no methods, fields, or string form.  To create one, it is
sufficient to say:

    bless $minKey, "MongoDB::MinKey";

=head2 MongoDB::MaxKey

C<MongoDB::MaxKey> is "greater than" any other value of any type.  This can be useful
for always returning certain documents last (or first).

C<MongoDB::MaxKey> has no methods, fields, or string form.  To create one, it is
sufficient to say:

    bless $minKey, "MongoDB::MaxKey";

