MongoDB allows programmers to save and query for data expressed in all of the basic PHP types, compound types (arrays, associative arrays, and objects), and a half-dozen classes provided by the MongoDB PHP driver (for regular expressions, dates, and other specialized applications).
null
true
, false
, and null
can be used as-is.
Numbers are distinct from strings in MongoDB: "123" does not match 123. Thus, if you want to make sure numbers are sorted and matched correctly, you must make sure that they are actually saved as numbers.
<?php
$doc = array("a" => 123, "b" => "123");
$collection->insert($doc);
$doc->find(array("a" => 123)); // matches
$doc->find(array("a" => "123")); // doesn't match
$doc->find(array("a" => 123.0)); // matches
$doc->find(array("b" => 123)); // doesn't match
$doc->find(array("b" => "123")); // matches
?>
As noted above, floating point numbers do compare with/match integer numbers as one would expect.
By default, on a 32-bit system, numbers are sent to the database as 32-bit integers. On a 64-bit system, they are sent as 64-bit integers. For backwards compatibility, all systems deserialize 64-bit integers as floating point numbers. Floating point numbers are not exact. If you need exact values, you must tweak your php.ini settings.
On a 32-bit system, if mongo.long_as_object
is set,
64-bit integers will be returns as MongoInt64
objects. The integer will be stored in the value
field
with perfect precision (as a string). You can also use
MongoInt64 to save 64-bit integers on 32-bit
machines.
On 64-bit systems, you can either set mongo.long_as_object
or set mongo.native_long
.
mongo.native_long
will return 64-bit integers and
"normal" PHP integers. You can use MongoInt32 to
save 32-bit integers on 64-bit machines.
You should set the mongo.long_as_object
and
mongo.native_long
behavior that you plan to use, even if
it is the default behavior (to protect against future changes to the
defaults).
See also: php.ini Options, MongoInt32, MongoInt64.
Strings must be UTF-8. Non-UTF-8 strings must either be converted to UTF-8 before being sent to the database or saved as binary data.
Regular expressions can be used to match strings, and are expressed using the MongoRegex class.
Non-UTF-8 strings, images, and any other binary data should be sent to the database using the MongoBinData type.
Dates can be created using the MongoDate class. They are stored as milliseconds since the epoch.
MongoTimestamp is not for saving dates or timestamps, it is used internally by MongoDB. Unless you are creating a tool that interacts with the internals of replication or sharding, you should use MongoDate, not MongoTimestamp.
The driver will automatically create an _id
field before
inserting a document (unless one is specified by the user). This field is an
instance of MongoId (called "ObjectId" in most other
languages).
These ids are 12 bytes long and composed of:
4 bytes of timestamp
No two records can have the same id if they were inserted at different times.
3 bytes machine id
No two records can have the same id if they were inserted on different machines
2 bytes thread id
No two records can have the same id if they were inserted by different threads running on the same machine.
3 bytes incrementing value
Each time an id is created, a global counter is incremented and used as the increment value of the next id.
MongoDB comes with a JavaScript engine, so you can embed JavaScript in queries (using a $where clause), send it directly to the database to be executed, and use it to perform aggregations.
For security, use MongoCode's scope
field to use PHP variables in JavaScript. Code that does not require
external values can either use MongoCode or just be
a string. See the
section on security for more
information about sending JavaScript to the database.
Arrays and objects can also be saved to the database. An array with ascending numeric keys will be saved as a an array, anything else will be saved as an object.
<?php
// $scores will be saved as an array
$scores = array(98, 100, 73, 85);
$collection->insert(array("scores" => $scores));
// $scores will be saved as an object
$scores = array("quiz1" => 98, "midterm" => 100, "quiz2" => 73, "final" => 85);
$collection->insert(array("scores" => $scores));
?>
If you query for these objects using the database shell, they will look like:
> db.students.find() { "_id" : ObjectId("4b06beada9ad6390dab17c43"), "scores" : [ 98, 100, 73, 85 ] } { "_id" : ObjectId("4b06bebea9ad6390dab17c44"), "scores" : { "quiz1" : 98, "midterm" : 100, "quiz2" : 73, "final" : 85 } }
The database can also save arbitrary PHP objects (although they will be returned as associative arrays). The fields are used for the key/value pairs. For example, a blog post might look like:
<?php
// the blog post class
class Post {
var $author;
var $content;
var $comments = array();
var $date;
public function __construct($author, $content) {
$this->author = $author;
$this->content = $content;
$this->date = new MongoDate();
}
public function setTitle($title) {
$this->title = $title;
}
}
// create a simple blog post and insert it into the database
$post1 = new Post("Adam", "This is a blog post");
$blog->insert($post1);
// there is nothing restricting the type of the "author" field, so we can make
// it a nested object
$author = array("name" => "Fred", "karma" => 42);
$post2 = new Post($author, "This is another blog post.");
// we create an extra field by setting the title
$post2->setTitle("Second Post");
$blog->insert($post2);
?>
From the database shell, this will look something like:
> db.blog.find() { "_id" : ObjectId("4b06c263edb87a281e09dad8"), "author" : "Adam", "content" : "This is a blog post", "comments" : [ ], "date" : "Fri Nov 20 2009 11:22:59 GMT-0500 (EST)" } { "_id" : ObjectId("4b06c282edb87a281e09dad9"), "author" : { "name" : "Fred", "karma" : 42 }, "content" : "This is a blog post", "comments" : [ ], "date" : "Fri Nov 20 2009 11:23:30 GMT-0500 (EST)", "title" : "Second Post" }
The driver will not detect reference loops in arrays and objects. For example, this will give a fatal error:
<?php
$collection->insert($GLOBALS);
?>
Fatal error: Nesting level too deep - recursive dependency?