Midwest PHP Call For Papers Open

MongoCollection::insert

(PECL mongo >=0.9.0)

MongoCollection::insertドキュメントをコレクションに追加する

説明

public MongoCollection::insert ( array|object $document [, array $options = array() ] ) : bool|array

データベースに送信する文字列は UTF-8 でなければなりません。 UTF-8 以外の文字列を送信した場合は MongoException がスローされます。非 UTF-8 文字列を追加 (あるいは問い合わせ) するには MongoBinData を使います。

パラメータ

document

配列あるいはオブジェクト。オブジェクトを使う場合は、 protected や private のプロパティは保持できません。

注意:

_id のキーあるいはプロパティを持たない場合は、 新しい MongoId インスタンスを作ってそれを代入します。 ただし、パラメータを参照で渡した場合は別です。

options

追加操作についてのオプションの配列。 現在利用可能なオプションは、以下のとおりです。

  • "fsync"

    Boolean 型で、デフォルトは FALSE です。 ジャーナリングが有効な場合、これは "j" とまったく同じ動きをします。 ジャーナリングが有効でない場合は、追加をディスク上のデータベースファイルに同期させるまで成功したと見なさないようになります。 TRUE にすると確認つき書き込みが暗黙のうちに設定され、"w" の値を 0 にします。

    注意: ジャーナリングが有効な場合は、"fsync" のかわりに "j" を使いましょう。 "fsync""j" を同時に指定すると、エラーになります。

  • "j"

    デフォルトは FALSE です。これを指定すると、追加をジャーナルに同期させるまで成功したと見なさないようになります。TRUE にすると確認付き書き込みと見なされ、"w" の設定を 0 に上書きします。

    注意: このオプションを使っているときにジャーナリングを無効にすると、MongoDB 2.6 以降ではエラーが発生して書き込みに失敗します。古いバージョンのサーバーでは、単純にオプションの指定を無視します。

  • "socketTimeoutMS"

    このオプションは、ソケット通信の制限時間を、ミリ秒単位で指定します。この時間内にサーバーからの反応がなければ、MongoCursorTimeoutException をスローします。この場合、サーバー側で書き込み処理が行われたのかどうかを判断できなくなります。-1 を指定すると、永遠にブロックします。MongoClient のデフォルト値は 30000 (30 秒) です。

  • "w"

    WriteConcerns を参照ください。MongoClient でのデフォルト値は 1 です。

  • "wTimeoutMS"

    このオプションは、書き込み確認を待つ制限時間をミリ秒単位で指定します。これが書き込み操作に適用されるのは、"w"1 より大きい場合のみです。というのも、タイムアウトはレプリケーションに関する機能だからです。この時間内に書き込み確認ができなかった場合は MongoCursorException をスローします。0 を指定すると、永遠にブロックし続けます。MongoClient でのデフォルトは 10000 ミリ秒 (10 秒) です。

以下のオプションは廃止予定です。使ってはいけません。

  • "safe"

    非推奨。write concernw オプションを使いましょう。

  • "timeout"

    非推奨。"socketTimeoutMS" のエイリアス。

  • "wtimeout"

    廃止予定。"wTimeoutMS" のエイリアスです。

返り値

"w" オプションが設定されている場合は、 追加の状況を含む配列を返します。 設定されていない場合は、 もし追加された配列が空でない場合に TRUE を返します (追加された配列が空の場合は MongoException をスローします)。

配列が返された場合、その中に含まれる要素は次のようになります。

ok

これはほぼ常に 1 です (ただし last_error 自体が失敗した場合は除く)。

err

このフィールドに null 以外の値が入っている場合は、直前の操作でエラーが発生しています。 このフィールドが設定されている場合、その内容は発生したエラーを表す文字列となります。

code

データベースのエラーが発生した場合に、そのエラーコードをクライアントに戻します。

errmsg

このフィールドが設定されるのは、データベースコマンドで何か問題が発生したときです。 ok を 0 にすることと組み合わせて使います。 たとえば、もし w が設定されているときにタイムアウトが発生すると、 errmsg は "timed out waiting for slaves" そして ok は 0 になります。 このフィールドが設定されている場合、その内容は発生したエラーを表す文字列となります。

n

直近の操作が insert、update あるいは remove だった場合に、影響を受けたドキュメントの数を返します。 追加操作の場合は、この値は常に 0 です。

wtimeout

直近の操作がレプリケーション待ちでタイムアウトしたかどうか。

waited

操作がタイムアウトするまでにどれだか待ったか。

wtime

w を設定して、かつ操作が成功した場合に、 w サーバーへのレプリケートにかかった時間。

upserted

upsert が発生した場合は、このフィールドに新しいレコードの _id が格納されます。upsert の場合は、このフィールドあるいは updatedExisting のいずれかが (エラーが発生しない限り) 必ず存在します。

updatedExisting

upsert が既存の要素を更新した場合に、このフィールドが true となります。 _id が格納されます。upsert の場合は、このフィールドあるいは upsearted のいずれかが (エラーが発生しない限り) 必ず存在します。

エラー / 例外

追加したドキュメントが空だったり長さがゼロのキーが含まれていたりした場合に MongoException をスローします。 protected や private なプロパティを持つオブジェクトを追加しようとすると、 キーの長さがゼロのエラーを引き起こします。

"w" オプションが設定されていて書き込みが失敗した場合に MongoCursorException をスローします。

"w" オプションの値が 1 より大きく設定されていて、操作の完了までの時間が MongoCursor::$timeout ミリ秒をこえた場合に MongoCursorTimeoutException をスローします。サーバー上での操作は止めません。これはクライアント側でのタイムアウトです。MongoCollection::$wtimeout はミリ秒です。

変更履歴

バージョン 説明
1.5.0

"wTimeoutMS" オプションが追加されました。これは "wtimeout" を置き換えるものです。 "wtimeout" を使うと E_DEPRECATED が発生します。

"socketTimeoutMS" オプションが追加されました。これは "timeout" を置き換えるものです。 "timeout" を使うと E_DEPRECATED が発生します。

"safe" を使うと E_DEPRECATED が発生します。

1.3.4 "wtimeout" オプションが追加されました。
1.3.0

"w" オプションが追加されました。

options パラメータで、boolean だけを渡して確認付きの書き込みを指定することができなくなりました。 同じことをするには array('w' => 1) (MongoClient のデフォルト) としなければなりません。

1.2.0 "timeout" オプションが追加されました。
1.0.11 "safe" が設定されている場合は、"not master" エラーで接続を切断するようになりました。
1.0.9

"safe" オプションに整数値がわたせるようになりました (以前は boolean のみでした)。

"fsync" オプションが追加されました。

"safe" オプションを使っている場合の返り値の型が配列に変わりました。 配列にはエラー情報が含まれています。"safe" オプションを使わない場合は、今までどおり boolean のままです。

1.0.2 二番目のパラメータがオプションの配列に変わりました。1.0.2 より前のバージョンでは、二番目のパラメータは "safe" オプションを表す boolean 値でした。
1.0.1 "safe" オプションが設定されていて追加に失敗した場合に MongoCursorException をスローするようになりました。

例1 MongoCollection::insert()_id の例

すでに存在しない場合は、_id フィールドを追加します。 パラメータの渡しかたによって、生成された _id に呼び出し元のコードからアクセスできるかどうかが変わります。

<?php

$m 
= new MongoClient();
$collection $m->selectCollection('test''phpmanual');

// 配列リテラルを使った場合は、生成された _id にはアクセスできません
$collection->insert(array('x' => 1));

// 値渡しした配列には _id が追加されています
$a = array('x' => 2);
$collection->insert($a);
var_dump($a);

// 参照渡しした配列からは _id は見えません
$b = array('x' => 3);
$ref = &$b;
$collection->insert($ref);
var_dump($ref);

// ラップする関数がコピーオンライトを引き起こさない場合は _id にアクセスできます
function insert_no_cow($collection$document)
{
    
$collection->insert($document);
}

$c = array('x' => 4);
insert_no_cow($collection$c);
var_dump($c);

// ラップする関数がコピーオンライトを引き起こす場合は _id にアクセスできません
function insert_cow($collection$document)
{
    
$document['y'] = 1;
    
$collection->insert($document);
}

$d = array('x' => 5);
insert_cow($collection$d);
var_dump($d);

?>

上の例の出力は、 たとえば以下のようになります。

array(2) {
  ["x"]=>
  int(2)
  ["_id"]=>
  object(MongoId)#4 (0) {
  }
}
array(1) {
  ["x"]=>
  int(3)
}
array(2) {
  ["x"]=>
  int(4)
  ["_id"]=>
  object(MongoId)#5 (0) {
  }
}
array(1) {
  ["x"]=>
  int(5)
}

例2 MongoCollection::insert() での確認つき書き込みの例

この例は、同じ _id を持つ二つの要素を追加しようとするものです。 w が設定されていれば、 MongoCursorException がスローされます。

<?php

$person 
= array("name" => "Joe""age" => 20);
$collection->insert($person);

// $person には _id フィールドができたので、
// もう一度追加しようとすると例外が発生します
try {
    
$collection->insert($person, array("w" => 1));
} catch(
MongoCursorException $e) {
    echo 
"Can't save the same person twice!\n";
}

?>

参考

add a note add a note

User Contributed Notes 6 notes

up
3
Christer Edvartsen
8 years ago
Also worth noting is that the MongoCollection::insert() method accepts objects as the first argument as well as arrays.

<?php
$data
= new stdClass;
$data->foo = 'foo';
$data->bar = 'bar';
$collection->insert($data);
var_dump($data->_id); // An instance of MongoId
?>

You can use other classes as well, but MongoCollection::insert() will fail if the object contains any protected or private properties. Public properties listed in the class will also be inserted:

<?php
class SomeClass {
    public
$foo = 'bar';
    public
$bar = 'foo';
}

$data = new SomeClass;
$data->foobar = 42;
$collection->insert($data);
var_dump($data->_id); // An instance of MongoId
?>

will result in a document with four elements:

_id => some mongoid
foo => 'bar'
bar => 'foo'
foobar => 42
up
2
gmail.com@mspreij
6 years ago
"Note: If the parameter does not have an _id key or property, a new MongoId instance will be created and assigned to it."

Note on note: this is true even if the insert *fails* (because of, say, duplicate key error). So even if no new document was inserted, the supplied array will still have a new MongoID key ->_id after the ->insert().

(which can make an attempted update after that fail, because you cannot update the _id value of a document..)
up
1
root at php dot net
6 years ago
_id and MongoId can be a source of problems that can make what would seem a trivial operation potentially complicated.

MongoId is not as predictable or safe as mysql's auto increment (an example that most PHP developers will be familiar with). _id is generated by the client rather than the server and so does not guarantee that it will be collision free.

By comparison, server side auto_increment mechanisms that PHP programmers might typically be used to wont collide until every single id had been used and with 64bits you can ensure this will almost never happen. You will also know when your table is getting full, and you can predict the rate. Most importantly, no matter the mechanism, being server side guarantees two clients wont collide. Mongo's behaviour is different to this.

Generally speaking inserting without specifying _id will tend to work, but there are some cases where is can fail or is particularly prone to failure.

The total size I believe is 96 bits. This might seem like a lot but the value is not created randomly. It is generated like this:

$unixtime . $machine_id . $pid . $counter

The counter starts from zero and is attached to each instance of MongoClient thus two MongoClient connections to the same server will almost certainly not work (produce a collision):

$m=new MongoWrapper();
$m->insert([0]);
$m=new MongoWrapper();
$m->insert([1]);

If MongoWrapper is not using a singleton for the connection or something to the same effect, the second call will most likely have the same unixtime. It will certainly have the same machine_id, pid and counter. The insert will fail.

If you are not using a singleton, this will work:

$m=new MongoWrapper();
$m->insert([0]);
$m->insert([1]);

You may also have difficulties in a multiple machine environment.

machine_id is a hash of gethostname. This is not guaranteed to be unique across machines. Some people do not set hostnames at all. If you do not ensure that your machines all have unique hostnames then if in the same second, two machines run a script that inserts, the second will have a 1 in 2^15 chance of colliding (assuming the most common PID max). Depending on how the system handles pids, the probability may actually be a little less. In short, make sure any host accessing your mongodb has a hostname that is unique among any other host accessing your mongodb.

I've seen some specs specify that counter should start from a random value but I highly recommend against this as it merely hides/obscures the problem.
up
1
mike at eastghost dot com
5 years ago
Attempting to insert() an array containing a NULL value followed by a blank space, in a non-utf8 encoding, results in the entire array (and all of its data) being ignored and the $opts array parameter being substituted instead as the data.
up
0
cuisdy at gmail dot com
6 years ago
Another rarity to keep in mind. Passing references has the same effect as passing a referenced object. Even if there's no different for PHP between those two, it's probably not evident. So, this code would not have the _id field added to $a:

<?php

$b
= &$a;

/* ... more code here ... */

$m = new MongoClient;
$collection = $m->test->phpmanual;

$a = array('x' => 12);

$collection->insert($a);
var_dump($a);
// array(1) { ["x"]=> int(12) }

?>

I've made the assignment above to show how this situation could happen, if you reassigned a var, for example. But it could be some normal referencing after giving $a its final value (but before calling insert), and the consequence would be the same: if a var is referenced, it won't get the _id appended.
up
0
John S.
7 years ago
Note, that the _id field will only be added to an inserted array if it does not already exist in the supplied array:

<?php
$data
= array('x' => 12);
var_dump($data);
$collection->insert($data);
var_dump($data);
?>

Will output something like:

array(1) {
  ["x"]=>
  int(12)
}
array(2) {
  ["x"]=>
  int(12)
  ["_id"]=>
  object(MongoId)#196 (1) {
    ["$id"]=>
    string(24) "503e21fc0605290912000000"
  }
}

however,

$data = array('x' => 12, '_id' => NULL);
var_dump($data);
$collection->insert($data);
var_dump($data);

will not have the same result:

array(2) {
  ["x"]=>
  int(12)
  ["_id"]=>
  NULL
}
array(2) {
  ["x"]=>
  int(12)
  ["_id"]=>
  NULL
}
To Top