Laravel中MongoDB子文档自动生成ObjectId(_id)的配置方法
Laravel中MongoDB子文档自动生成ObjectID的实现方法
不用手动给每个子文档写new \MongoDB\BSON\ObjectID(),可以通过模型层的处理自动完成,下面是几种可行的方案:
方案一:模型内部监听保存事件
在Product模型的boot方法中监听saving事件,保存前自动为skus数组里的子文档补全_id:
namespace App\Models; use Illuminate\Database\Eloquent\Model; use MongoDB\BSON\ObjectID; class Product extends Model { protected $connection = 'mongodb'; protected $collection = 'products'; protected static function boot() { parent::boot(); static::saving(function ($product) { if (isset($product->skus) && is_array($product->skus)) { $product->skus = array_map(function ($sku) { // 仅当子文档没有_id时生成ObjectID if (!isset($sku['_id'])) { $sku['_id'] = new ObjectID(); } return $sku; }, $product->skus); } }); } }
方案二:使用字段修改器
给skus字段定义修改器,赋值时自动处理子文档:
class Product extends Model { protected $connection = 'mongodb'; protected $collection = 'products'; public function setSkusAttribute($value) { $processedSkus = array_map(function ($sku) { if (!isset($sku['_id'])) { $sku['_id'] = new ObjectID(); } return $sku; }, $value); $this->attributes['skus'] = $processedSkus; } }
使用时直接按原来的代码赋值即可,修改器会自动处理skus数组。
方案三:全局Trait复用(多模型通用)
如果多个模型都有子文档需要自动生成_id,可以封装成Trait,避免重复代码:
首先创建Trait:
namespace App\Traits; use MongoDB\BSON\ObjectID; trait AutoSubdocumentObjectId { protected static function bootAutoSubdocumentObjectId() { static::saving(function ($model) { // 模型中需定义$subdocumentFields指定要处理的字段 if (property_exists($model, 'subdocumentFields')) { foreach ($model->subdocumentFields as $field) { if (isset($model->{$field}) && is_array($model->{$field})) { $model->{$field} = array_map(function ($item) { if (!isset($item['_id'])) { $item['_id'] = new ObjectID(); } return $item; }, $model->{$field}); } } } }); } }
然后在Product模型中使用:
class Product extends Model { use \App\Traits\AutoSubdocumentObjectId; protected $connection = 'mongodb'; protected $collection = 'products'; protected $subdocumentFields = ['skus']; // 指定需要处理的子文档字段 }
以上三种方案都能实现你的需求,执行原来的代码时,未手动指定_id的子文档会自动生成ObjectID。
内容的提问来源于stack exchange,提问作者kanu mahajan
相关产品推荐
相关产品推荐

