# 型

## 目次

- MongoId
- MongoCode
- MongoDate
- MongoRegex
- MongoBinData
- MongoInt32
- MongoInt64
- MongoDBRef
- MongoMinKey
- MongoMaxKey
- MongoTimestamp

MongoDB では、PHP のすべての基本データ型や複合型 (配列、連想配列 そしてオブジェクト) を保存したり問い合わせたりすることができます。 それ以外にも、MongoDB PHP ドライバには (正規表現や 日付、その他さまざまな用途に特化した) クラスが用意されています。

## Boolean および `NULL`

`TRUE`、`FALSE` および `NULL` はそのままの型で使えます。

## 数値

MongoDB では数値と文字列は区別されます。"123" は 123 とマッチしません。 したがって、数値のソートやマッチングを正しく行うには、数値として保存しなければなりません。

`<?php
$doc = array("a" => 123, "b" => "123");
$collection->insert($doc);
$doc->find(array("a" => 123)); // マッチします
$doc->find(array("a" => "123")); // マッチしません
$doc->find(array("a" => 123.0)); // マッチします
$doc->find(array("b" => 123)); // マッチしません
$doc->find(array("b" => "123")); // マッチします
?>`

上に示したように、浮動小数点数と整数の比較やマッチングは期待通りにできます。

## 大きな数値

デフォルトでは、32 ビットシステム上では数値をデータベースに送信するときには 32 ビット整数型となります。 64 ビットシステム上では数値をデータベースに送信するときには 64 ビット整数型となります。 過去との互換性を保つため、64 ビット整数型をデシリアライズするとすべてのシステムで浮動小数点数となります。 浮動小数点数には誤差があります。正確な値が必要なら php.ini の設定をしましょう。

32 ビットシステム上では、mongo.long_as_object が設定されていると 64 ビット整数値が MongoInt64 オブジェクトとして返されます。 整数値は、value フィールドに完全な精度で (文字列として) 格納されます。 MongoInt64 を使えば、64 ビット整数値を 32 ビットマシン上に保存することもできます。

64 ビットシステム上では、mongo.long_as_object あるいは mongo.native_long を設定することができます。 mongo.native_long は、64 ビット整数値を "通常の" PHP の整数型で返します。MongoInt32 を使えば、 32 ビット整数値を 64 ビットマシン上に保存することができます。

mongo.long_as_object や mongo.native_long の挙動は、使おうとする内容にあわせて設定するべきです。 たとえデフォルトの挙動であっても、明示的に設定しておくことが大切です (将来もしデフォルトの設定が変わっても、その影響を受けずにすみます)。

php.ini のオプション、 MongoInt32、そして MongoInt64 も参照ください。

## 文字列

文字列は UTF-8 でなければなりません。非 UTF-8 文字列は、UTF-8 に変換してからデータベースに送信するか、あるいはバイナリデータとして保存しなければなりません。

正規表現を使った文字列のマッチングができます。正規表現には MongoRegex クラスを使います。

## バイナリデータ

非 UTF-8 文字列や画像その他のバイナリデータをデータベースに送信するときには MongoBinData 型を使わなければなりません。

## 日付

日付を作成するには MongoDate クラスを使います。 ここにはエポックからの経過ミリ秒数が格納されます。

MongoTimestamp は日付やタイムスタンプを保存するためのものではなく、 MongoDB の内部で使うものです。レプリカやシャーディングの内部構造を扱うツールを書いているのでない限り、 MongoTimestamp ではなく MongoDate を使うべきです。

## 一意な Id

ドライバは、ユーザーが明示的に指定しない限り、自動的に _id フィールドを作成してからドキュメントを追加します。このフィールドは MongoId (いわゆる "オブジェクト ID") のインスタンスです。

ID は 12 バイトで、このような構造です。

- タイムスタンプ 4 バイト

  別の時刻に追加されたレコードが同じ id になることはありません。

- マシン id 3 バイト

  別のマシンから追加されたレコードが同じ id になることはありません。

- スレッド id 2 バイト

  同じマシン上の別のスレッドから追加されたレコードが同じ id になることはありません。

- 増分 3 バイト

  id が新たに作られるたびにグローバルなカウンタがひとつ増加します。 次の id を作るときに、この値を使います。

従って、同一マシン上の単一のプロセスで 1 秒間に 256^3 件 (1600万件以上) のレコードを追加 (増分領域を使い切る) しようとしない限り、 同じ id になることはありません。

## JavaScript

MongoDB には JavaScript エンジンが組み込まれているので、JavaScript をクエリに ($where 句で) 組み込んで直接データベースに送信して実行し、 集約することができます。

セキュリティ上、MongoCode の scope フィールドを使って PHP の変数を JavaScript に渡します。外部の値を使わないコードの場合は MongoCode を使っても単なる文字列を使ってもかまいません。 JavaScript をデータベースに送信することに関する詳細な情報は セキュリティの節 を参照ください。

## 配列およびオブジェクト

配列やオブジェクトもデータベースに格納することができます。 数値添字の配列は配列として、 それ以外のものはすべてオブジェクトとして格納されます。

`<?php
// $scores は配列として格納されます
$scores = array(98, 100, 73, 85);
$collection->insert(array("scores" => $scores));
// $scores はオブジェクトとして格納されます
$scores = array("quiz1" => 98, "midterm" => 100, "quiz2" => 73, "final" => 85);
$collection->insert(array("scores" => $scores));
?>`

データベースのシェルからこれらのオブジェクトを問い合わせると、このようになります。

    > db.students.find()
    { "_id" : ObjectId("4b06beada9ad6390dab17c43"), "scores" : [ 98, 100, 73, 85 ] }
    { "_id" : ObjectId("4b06bebea9ad6390dab17c44"), "scores" : { "quiz1" : 98, "midterm" : 100, "quiz2" : 73, "final" : 85 } }

任意の PHP オブジェクトもデータベースに格納することができます (返されるときは連想配列となります)。 フィールドは キー/値 のペアに使います。 たとえば、blogへの投稿を表す次のようなオブジェクトを考えましょう。

`<?php
// blog投稿クラス
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;
}
}
// 単純なblog投稿を作り、データベースに追加します
$post1 = new Post("Adam", "This is a blog post");
$blog->insert($post1);
// "author" フィールドの型には何も制約がないので、
// オブジェクトをネストさせることができます
$author = array("name" => "Fred", "karma" => 42);
$post2 = new Post($author, "This is another blog post.");
// タイトルを設定して、別のフィールドを追加することができます
$post2->setTitle("Second Post");
$blog->insert($post2);
?>`

データベースのシェルからは、次のように見えます。

    > 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" }

このドライバは、配列やオブジェクトの循環参照を検出することができません。 たとえば、これは致命的なエラーとなります。

`<?php
$collection->insert($GLOBALS);
?>`

    Fatal error: Nesting level too deep - recursive dependency?

再帰構造になる可能性のあるドキュメントを追加しなければならない場合は、 ドライバに渡す前に自分でチェックしておかなければなりません。