MongoCollection::update

(PECL mongo >=0.9.0)

MongoCollection::update指定した条件にもとづいてレコードを更新する

説明

public MongoCollection::update ( array $criteria , array $new_object [, array $options = array() ] ) : bool|array

パラメータ

criteria

更新したいオブジェクトの条件。

new_object

マッチするレコードを更新するオブジェクト。 更新演算子を含めたり (特定のフィールドだけの更新用)、 ドキュメント全体を上書きしたりできます。

options

更新時のオプションの配列。 現在利用可能なオプションは、以下のとおりです。

  • "upsert"

    $criteria にマッチするレコードが見つからない場合に 新しいドキュメントを追加します。

    新しいドキュメントを追加するときに $new_object にアトミックな修正子 ($ 演算子) が含まれていれば、この操作を $criteria パラメータに適用して新しいドキュメントを作ります。 $new_object がアトミックな修正子を含まない場合は、 そのままの形式で新しいドキュメントに使います。 詳細は、以下の upsert の例を参照ください。

  • "multiple"

    $criteria にマッチするすべてのドキュメントを更新します。 MongoCollection::update()MongoCollection::remove() と正反対の動きをします。 デフォルトでは、マッチするすべてのドキュメントではなく ひとつのドキュメントだけを更新するのです。 複数ドキュメントを更新したいのかそうでないのかは、 常に指定しておくことを推奨します。 将来、データベースのデフォルトの挙動が変わる可能性があるからです。

  • "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 を返します。

状態を表す配列のフィールドについては MongoCollection::insert() のドキュメントを参照ください。

エラー / 例外

"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 だけを渡して upsert を指定することができなくなりました。 同じことをするには array('upsert'' => true) としなければなりません。

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

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

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

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

1.0.5 "safe" オプションが追加されました。
1.0.1 options パラメータが boolean から配列に変わりました。 1.0.1 より前のバージョンでは二番目のパラメータはオプションの boolean 値で、upsert を指定するものでした。

例1 MongoCollection::update()

address フィールドをドキュメントに追加します。

<?php

$c
->insert(array("firstname" => "Bob""lastname" => "Jones" ));
$newdata = array('$set' => array("address" => "1 Smith Lane"));
$c->update(array("firstname" => "Bob"), $newdata);

var_dump($c->findOne(array("firstname" => "Bob")));

?>

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

array(4) {
  ["_id"]=>
  object(MongoId)#6 (0) {
  }
  ["firstname"]=>
  string(3) "Bob"
  ["lastname"]=>
  string(5) "Jones"
  ["address"]=>
  string(12) "1 Smith Lane"
}

例2 MongoCollection::update() での upsert

upsert を使うとコードを簡潔にすることができます。 オブジェクトが存在しない ($criteria に基づく) 場合は新たに作成し、 存在する場合はそれを更新するという操作を一行で書けるからです。

次の例では、$new_object にアトミックな修正子が含まれています。 コレクションは空なので upsert は新たなドキュメントを追加することになり、 これらの操作を $criteria パラメータに適用してドキュメントを作ります。

<?php

$c
->drop();
$c->update(
    array(
"uri" => "/summer_pics"),
    array(
'$inc' => array("page hits" => 1)),
    array(
"upsert" => true)
);
var_dump($c->findOne());

?>

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

array(3) {
  ["_id"]=>
  object(MongoId)#9 (0) {
  }
  ["uri"]=>
  string(12) "/summer_pics"
  ["page hits"]=>
  int(1)
}

$new_object がアトミックな修正子 ($ 演算子) を含まない場合、upsert は $new_object をそのままの形式で新しいドキュメントに使います。 これは通常の update の挙動と同じです。 アトミックな修正子を使わなければ、ドキュメント全体が上書きされます。

<?php

$c
->drop();
$c->update(
    array(
"name" => "joe"),
    array(
"username" => "joe312""createdAt" => new MongoDate()), 
    array(
"upsert" => true)
);
var_dump($c->findOne());

?>

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

array(3) {
  ["_id"]=>
  object(MongoId)#10 (0) {
  }
  ["username"]=>
  string(6) "joe312"
  ["createdAt"]=>
  object(MongoDate)#4 (0) {
  }
}

例3 MongoCollection::update() での複数更新

デフォルトでは MongoCollection::update() は、 $criteria にマッチするドキュメントが複数見つかっても最初のものだけを更新します。 必要なら、"multiple" オプションでその挙動を変えることができます。

この例は、翌日が誕生日である全員に "gift" フィールドを追加します。

<?php

$today 
= array('$gt' => new MongoDate(), '$lt' => new MongoDate(strtotime("+1 day")));
$people->update(
    array(
"birthday" => $today),
    array(
'$set' => array('gift' => $surprise)),
    array(
"multiple" => true)
);

?>

参考

更新に関するドキュメント および » MongoDB コアメント を参照ください。

add a note add a note

User Contributed Notes 8 notes

up
18
nerds at limeworks dot com dot au
13 years ago
For anyone referencing records by the Mongo _id object, it's important to recognise that it is in fact an object, and not a string.

If you have a record with a Mongo ID of say "4e519d5118617e88f27ea8cd" that you are trying to retrieve or update, you cannot search for it using something like:
<?php
$m
= new Mongo();
$db = $m->selectDB('db');
$collection = 'collection';
$db->$collection->findOne(array('_id', '4e519d5118617e88f27ea8cd'));
?>

There is some documentation that mentions simple conversion to string will solve this, but I have found the only reliable way to locate records based on their ID is to first pass it to MondoID(), then use that for reference.

Something like this will be far more reliable:
<?php
$m
= new Mongo();
$db = $m->selectDB('db');
$collection = 'collection';
$mongoID = new MongoID('4e519d5118617e88f27ea8cd');
$db->$collection->findOne(array('_id', $mongoID));
?>

This may prove useful for anyone using the ID object like an auto-increment database key would be used in MySQL or similar.
up
13
joshuadburns at hotmail dot com
13 years ago
Please note under optional third parameter "options":

While the official MongoDB documentation references the keyword "multi" to flag the use of multiple updates, the PHP implementation uses the key "multiple" instead.

This may cause a little confusion if you're basing your keys on the OFFICIAL MongoDB documentation.
up
5
Vasiliy Makogon
11 years ago
if you want emulate on mongoDb "insert on duplicate key update" in SQL notation, you must use flag "upsert" with "$set" in "update" operation.

In this sample uses unique key (user id and product id) and date user visit  product:page. Each execute this code make update 'lasttime' field:

<?php
$client
= new \MongoClient(MONGO_DB);
$users = $client->users;
$last_views = $users->createCollection('last_views');
// create unique index
$result = $last_views->ensureIndex(
    array(
"user_id" => 1, "warecode" => 1),
    array(
"unique" => 1)
);

$uviews = new \stdClass();
$uviews->user_id = $this->user_id;
$uviews->warecode = $this->warecode;

$res = $users->last_views->update(
   
$uviews,
    array(
'$set' => array('lasttime' => new \MongoTimestamp())),
    array(
'upsert' => true)
);
?>
up
1
jeff at canuckistani dot ca
14 years ago
The return type of update changed in 1.09 if you are using safe => TRUE. It now returns something that looks like the info returned by MongoDB::lastError:

Array
(
    [err] =>
    [updatedExisting] => 1
    [n] => 1
    [ok] => 1
)
up
0
bronius at bcswebstudio dot com
10 years ago
Re. nerds @ limeworks comment:
Thanks for your helpful tip - right what I was looking for.  One note, though: Instead of comma, it's a => as in:
<?php
...->findOne(array('_id' => $mongoID);
?>
up
-3
rithish[at]gmail[dot]com
14 years ago
Do note, for incrementing a value using $inc, typecast the value to an integer before passing the new object to update().

<?php
$votes
= (int) $votes;
$newData = array('$inc' => array('votes'=>$votes));
$c->update(array("firstname" => "Bob"), $newData);
?>

This is especially noteworthy, if you are taking values from $_GET and pushing them for increment.
up
-3
bradzo0647 at gmail dot com
10 years ago
A need for an app was to add a new entry to the industries collection if it didn't already exist, and pass that "string" _id back to the caller to add it to the businesses collection (as a string also - database design by others.... :))

function GetIndustryID($db, $industry_name_eng, $industry_name_rus) {

// $db is the MongoDB database object
// $industry_name_eng is English of the industry name
// $industry_name_rus is Russian of the industry name

    if ( $industry_name_eng == "" && $industry_name_rus == "" ) {
        return "";
        exit;
    }
   
    // lookup russian version
    // of industry name from industries collection and try to return the _id
  
    // if not found, add this as a new document and return its _id

        // $c_ind = industry collection object
        // "industries" is the collection name

    $c_ind = $db->industries;

// you could use findOne here....
    $cursor = $c_ind->find(array('industry_name.russian' => $industry_name_rus));

    if ( $cursor->hasNext() ) {
        foreach ( $cursor as $document ) {         
            $id = $document['_id'];
        }
    } else {
        // not found here - go add it
        $document = array(
            "industry_id" => "",
            "industry_name" => array("english" => $industry_name_eng, "russian" => $industry_name_rus )
        );
        $db->industries->insert($document);
        $id = $document['_id'];   
       
        // update the industry_id in the industries collection
        // with the id returned - because we just added it, and
        // we need the industry_id the same as the _id
       
        // see: http://php.net/manual/en/mongocollection.update.php
       
        // update ( array $criteria , array $new_object [, array $options = array() ] )

                // note how I cast the MongoID "object" to a string
        $document['industry_id'] = (string)$id;
                // the $id in the next line is the ObjectID, not a string.
        $db->industries->update(array("_id" => $id), $document, array("upsert" => true));
    }
  
    return (string)$id;
              
}

Results: (using RoboMongo)
{
    "_id" : ObjectId("5427acf7a495dbd420b2e2ea"),
    "industry_id" : "5427acf7a495dbd420b2e2ea",
    "industry_name" : {
        "english" : "Oil and Gas",
        "russian" : "Нефть, Газ, Энергетика"
    }
}

It took me ages to work this out. Hope it helps someone else.
up
-5
Nanhe Kumar
8 years ago
$inc and set in one statement
<?php
    $m
= new Mongo();
   
$db = $m->selectDB('db');
   
$collection = 'collection';
   
$db->$collection->insert(array("firstname" => "Nanhe", "lastname" => "Kumar","attempt"=>1 ));
   
$newdata = array('$inc'=>array("attempt"=>1),'$set' => array("address" => "Delhi India"));
   
$db->$collection->update(array("firstname" => "Nanhe"), $newdata);
?>
To Top