Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

wonder95's avatar

Laravel 12 with MongoDB: No id/_id value stored/returned when creating model.

In Larvavel 11 with mongodb/laravel-mongodb v4.8 in my LinkModel, I have this getter

    public function getSourceLinkAttribute(): string
    {
        return $this
            ->linksFor('source')
            ->first()
            ->id;
    }

where linksFor() is this:

    public function linksFor(string $type): Collection
    {
        return collect($this->attributes['links'] ?? [])
            ->transform(function ($item) {
                return new LinkModel($item);
            })
            ->filter(function ($item) use ($type) {
                return $item->type === $type;
            });
    }

in LinkModel, $fillable = ['_id', 'type', and 'title'], and in the MongoDB records, it looks like this

"links" : [
    {
        "_id" : "https://acquisitiongateway.gov/forecast/resources/8826",
        "type" : "source"
    },
    {
        "_id" : "https://sam.gov/opp/ecad9d49c41547d38436e059165aec4e/view",
        "type" : "sam"
    }
],

In Laravel 12 with mongodb/laravel-mongodb v5 this no longer works, because

$this->linksFor('source')->first()->_id;

returns null, and so does

$this->linksFor('source')->first()->id;

When inspecting the returned LinkModel from linksFor() now, there is no id or _id value in it..

When using in tinker if I do this

new App\Models\LinkModel(['_id' => 'https://sam.gov', 'type' => 'source']);

and when I show the model it shows this

= App\Models\LinkModel {#7861
    _id: "https://govtribe.com",
    type: "source",
    +title: "govtribe.com",
  }

so it seems the _id value is getting saved there. One way I've figured out to get around this is with forceFill()

            ->transform(function ($item) {
              return (new LinkModel())->forceFill($item);
              
            })

but that doesn't seem right.

  1. Why am I getting no id/_id value in my LinkModel?
  2. How do I fix it?
0 likes
1 reply
LaryAI's avatar
Level 58

The issue you're encountering with the id or _id not being populated in your LinkModel is likely due to changes in how the mongodb/laravel-mongodb package handles attributes in the newer version. Here are some steps to address the problem:

1. Understanding the Issue

In MongoDB, the default identifier field is _id. When using the mongodb/laravel-mongodb package, it should automatically map the _id field to the id attribute in your Eloquent models. However, if this mapping is not happening, it could be due to changes in the package or how the model is being instantiated.

2. Solution

To ensure that the _id field is correctly mapped to the id attribute, you can explicitly define the $primaryKey in your LinkModel and ensure that the attribute casting is correctly set up.

Step-by-Step Solution

  1. Define the Primary Key:

    In your LinkModel, explicitly set the $primaryKey to _id:

    class LinkModel extends \Jenssegers\Mongodb\Eloquent\Model
    {
        protected $primaryKey = '_id';
        protected $fillable = ['_id', 'type', 'title'];
    }
    
  2. Attribute Casting:

    Ensure that the _id field is cast to a string, as MongoDB IDs are typically strings:

    class LinkModel extends \Jenssegers\Mongodb\Eloquent\Model
    {
        protected $primaryKey = '_id';
        protected $fillable = ['_id', 'type', 'title'];
        protected $casts = [
            '_id' => 'string',
        ];
    }
    
  3. Check the Collection Transformation:

    When transforming the collection, ensure that the attributes are correctly set. If forceFill() works, it indicates that the attributes are not being set correctly during instantiation. You can continue using forceFill() if it resolves the issue, but ensure that the model is correctly configured to handle the attributes:

    public function linksFor(string $type): Collection
    {
        return collect($this->attributes['links'] ?? [])
            ->transform(function ($item) {
                return (new LinkModel())->forceFill($item);
            })
            ->filter(function ($item) use ($type) {
                return $item->type === $type;
            });
    }
    

3. Conclusion

By explicitly setting the primary key and ensuring proper attribute casting, you should be able to resolve the issue with the id or _id not being populated. If the problem persists, consider checking the package documentation for any additional changes or updates that might affect how models are handled in the newer version.

Please or to participate in this conversation.