0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Laravel, MongoDB]mongoDBのupdate処理時の注意点

Posted at

はじめに

業務でLaravel×MongoDBを使う場面でMongoDBはLaravel標準ではデフォルトでサポートしていないので、MongoDBをEloquentチックに使える**laravel-mongodb** というライブラリを使っております。

その中でEloquentとはちょっと違う挙動で戸惑った時のメモです。

前提

環境は

  • Laravel 8.0.17
  • laravel-mongodb 3.8.4

ライブラリはインストール済みです

composer require jenssegers/mongodb

DB

今回mongoDBにあるテーブルはtalksというテーブル

カラム名 説明
_id string 一意のID
body string 本文
read_at datetime 既読時間
created_at datetime 作成時間

ソースコード

モデル

App/Models/Talks.php

<?php

namespace App\Models;

use Jenssegers\Mongodb\Eloquent\Model;

class Talk extends Model
{
    /**
     * コレクション名.
     *
     * @var string
     */
    protected $collection = 'talks';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'body',
        'read_at',
    ];

    /**
     * 保存時、取得時にMongoDateとCarbonの形式の変換を行うカラムの設定。
		 *
     * @var array
     */
    protected $dates = [
		'read_at'
	];
}

use Jenssegers\Mongodb\Eloquent\Model;でライブラリを読み込んで、extendsしています

コントローラ

↓App\Controllers\TalkController.php

public function detail($id)
{
		...
		$talk = Talk::findOrFail($id);
        $talk->whereNull('read_at')->update(['read_at' => now()]);
		...
}

挙動としてはトークの詳細画面に遷移した際に、「未読状態」のトークのread_atに日時(Carbon)を入れて「既読状態」にする、といった感じ

動作確認

想定挙動

上記のコードでTalkControllerのdetailアクションを実行してみた

想定挙動はCarbonのnow()を保存しに行くので、以下の様にISODate(<現在日時>)になると思っている。

{
	...
    read_at: ISODate('2022-07-16T00:56:15.378Z'),
	...
    created_at: ISODate('2022-07-16T00:56:15.378Z')
}

実際の挙動

ただ、実際は以下のようになった

{
	...
    read_at: {},
	...
    created_at: ISODate('2022-07-16T00:56:15.378Z')
}

空のオブジェクトが入ってきた。。。

調査結果

原因

mongoDBへのupdate()処理時だけこの挙動になるとのissueを見つけた

※どうやらsave()はnow()でも想定通りの挙動になるらしい
※そして、isssueに挙がっている挙動ではdateとして日時が保存されたオブジェクトが保存されるらしい。ちょっと自分の挙動と違ったが、一旦スルーする。

対応策

挙動は違えど、「Carbonを使っている」という共通点があったので上記issueに記載してあった「UTCDateTimeクラスを使いましょう」という助言に従い、以下の形で修正した

↓App\Controllers\TalkController.php

public function detail($id)
{
		$talk->whereNull('read_at')->update(['read_at' => new UTCDateTime(new DateTime)]);
}

現在時刻が欲しいのでDateTimeクラスのインスタンスを引数にしてみた

再度detailアクションを実行してみると以下の様に想定通りの値に更新されていることを確認

{
		...
    read_at: ISODate('2022-07-16T00:56:15.378Z'),
		...
    created_at: ISODate('2022-07-16T00:56:15.378Z')
}

やったね。

所見

save()メソッドはCarbon使えるのに、updateは使えないのか…というのは意外な落とし穴でした。

mongoDBの使用パターン上、複数レコードの特定カラム(今回だとtalksのread_at)を一気に更新するって処理って結構多いはずなので、ここはCarbonでも対応できるようになってほしいなあ、と思った僕のワガママです笑

mongoDBは少し触りだしたばかりなので、引き続き気づきがあれば投稿します。

最後までお読みいただきありがとうございました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?