「MongoDBのコレクションから最新レコードを取得したい」
「MongoDBでデータ登録順にDocumentを並べたい」
このような場合には、この記事の内容が参考となります。
この記事では、MongoDBから最新レコードを取得する方法を解説しています。
本記事の内容
- findOneによる最新レコードの取得
- タイムスタンプでは正確な登録順を認識できない
- PHPにおけるMongoDBへのデータ登録
それでは、上記に沿って解説していきます。
findOneによる最新レコードの取得
これ以降の説明では、PHPからMongoDBに接続済みであることが前提です。
もし、まだ未接続であるなら、次の記事を参考にしてください。
では、findOneによる最新レコードの取得を説明していきます。
ここでは、sortという名称のcollectionを利用します。
このcollectionには、10行のデータを登録しています。
登録に関しては、「PHPにおけるMongoDBへのデータ登録」をご覧ください。
> db.sort.find() { "_id" : ObjectId("61c309e0c1cadb61081fed42"), "no" : 1, "datetime" : ISODate("2021-12-22T11:20:00.194Z") } { "_id" : ObjectId("61c309e0c1cadb61081fed43"), "no" : 2, "datetime" : ISODate("2021-12-22T11:20:00.321Z") } { "_id" : ObjectId("61c309e0c1cadb61081fed44"), "no" : 3, "datetime" : ISODate("2021-12-22T11:20:00.322Z") } { "_id" : ObjectId("61c309e0c1cadb61081fed45"), "no" : 4, "datetime" : ISODate("2021-12-22T11:20:00.322Z") } { "_id" : ObjectId("61c309e0c1cadb61081fed46"), "no" : 5, "datetime" : ISODate("2021-12-22T11:20:00.322Z") } { "_id" : ObjectId("61c309e0c1cadb61081fed47"), "no" : 6, "datetime" : ISODate("2021-12-22T11:20:00.322Z") } { "_id" : ObjectId("61c309e0c1cadb61081fed48"), "no" : 7, "datetime" : ISODate("2021-12-22T11:20:00.323Z") } { "_id" : ObjectId("61c309e0c1cadb61081fed49"), "no" : 8, "datetime" : ISODate("2021-12-22T11:20:00.323Z") } { "_id" : ObjectId("61c309e0c1cadb61081fed4a"), "no" : 9, "datetime" : ISODate("2021-12-22T11:20:00.323Z") } { "_id" : ObjectId("61c309e0c1cadb61081fed4b"), "no" : 10, "datetime" : ISODate("2021-12-22T11:20:00.323Z") }
最新のデータは、「no = 10」のデータとなります。
このデータを取得するためのコードは、以下。
<?php require 'vendor/autoload.php'; $client = new MongoDB\Client("mongodb://localhost:27017"); $collection = $client->test->sort; $result = $collection->findOne( [], [ 'sort' => ['_id' => -1] ] ); var_dump($result); ?>
上記コードを実行すると、次の結果が表示されます。
object(MongoDB\Model\BSONDocument)#19 (1) { ["storage":"ArrayObject":private]=> array(3) { ["_id"]=> object(MongoDB\BSON\ObjectId)#17 (1) { ["oid"]=> string(24) "61c309e0c1cadb61081fed4b" } ["no"]=> int(10) ["datetime"]=> object(MongoDB\BSON\UTCDateTime)#18 (1) { ["milliseconds"]=> string(13) "1640172000323" } } }
他にも方法はありますが、この方法が最も手軽で確実です。
「_id」は、自動的に各レコード(Document)に登録される値になります。
何も指定しないと、ObjectIdオブジェクトが登録されます。
ObjectIdは、BSON形式のデータです。
ObjectId — MongoDB Manual
https://docs.mongodb.com/manual/reference/method/ObjectId/
ObjectIdの詳細は、上記ページで確認できます。
簡単に言うと、ObjectIdにはタイムスタンプの情報が含まれています。
さらに、タイムスタンプに加えてデータ発生順の情報も含まれています。
そのため、タイムスタンプだけの場合より表示順序を確実に認識できるのです。
タイムスタンプだけに頼ると、最新レコードの取得に失敗します。
その失敗例を次で説明します。
タイムスタンプでは正確な登録順を認識できない
sortコレクションをdatetime(タイムスタンプ)を降順にしてfindOneで取得してみます。
以下のコードを利用します。
<?php require 'vendor/autoload.php'; $client = new MongoDB\Client("mongodb://localhost:27017"); $collection = $client->test->sort; $result = $collection->findOne( [], [ 'sort' => ['datetime' => -1] ] ); var_dump($result); ?>
フィールドが「_id」から「datetime」に変わっただけです。
このコードの結果は、以下。
object(MongoDB\Model\BSONDocument)#19 (1) { ["storage":"ArrayObject":private]=> array(3) { ["_id"]=> object(MongoDB\BSON\ObjectId)#17 (1) { ["oid"]=> string(24) "61c309e0c1cadb61081fed48" } ["no"]=> int(7) ["datetime"]=> object(MongoDB\BSON\UTCDateTime)#18 (1) { ["milliseconds"]=> string(13) "1640172000323" } } }
「no = 7」のデータが取得されています。
これは、最新レコードではありません。
この事象の原因は、次の結果を見ればわかります。
これは、sortコレクションをタイムスタンプを基準に降順で表示したモノです。
利用したコードは、以下。
<?php require 'vendor/autoload.php'; $client = new MongoDB\Client("mongodb://localhost:27017"); $collection = $client->test->sort; $cursor = $collection->find( [], [ 'sort' => ['datetime' => -1], ] ); foreach ($cursor as $document) { echo $document["_id"]; echo "@"; echo $document["no"]; echo "@"; echo (string)$document["datetime"]; echo "<br />"; } ?>
タイムスタンプは、タイミングによって同じデータになります。
noが7〜10までは、すべて同じタイムスタンプで登録されています。
実際は、ミリ秒レベルで同じなることは稀かもしれません。
しかし、同じなる可能性はあります。
よって、タイムスタンプをレコード登録順の基準に用いることはできません。
それよりは、ObjectIdという便利なモノを利用すべきです。
そして、それは「_id」として自動的にレコードに登録されます。
PHPにおけるMongoDBへのデータ登録
10行のデータは、次のコードで登録しています。
<?php require 'vendor/autoload.php'; $client = new MongoDB\Client("mongodb://localhost:27017"); $collection = $client->test->sort; for($i=0; $i<10; $i++) { $no = $i + 1; $datetime = new MongoDB\BSON\UTCDateTime(); $insertOneResult = $collection->insertOne([ 'no' => $no, 'datetime' => $datetime ]); } ?>
MongoDBの日付・時刻(Date型)を用いています。
MongoDBの日付・時刻(Date型)については、次の記事で説明しています。