LaraNewDev's avatar

firstOrCreate on json field

Hello,

I have a tag system which is multilingual. Tags are stored in a table with a JSON field. This field holds translations as key->value pairs. This is my schema:

         Schema::create('tags', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->json('name');
            $table->timestamps();
        });       		

I want to use FirstOrCreate because I assign tags during post creation, and I don't want to have two times the same tag in database. I do it like this:

$tag = tag::firstOrCreate([
    'name' => 
        [
            'es' => $tagItem['es'],
            'en' => $tagItem['en']
        ],
]);

Before model was multilingual and column was not json type, it worked. The behaviour now is that tags are always created. It seems that firstOrCreate cannot locate the existing record. Next picture clarifies a bit. https://i.imgur.com/N0zYtcT.jpg

Is this a syntax issue? A bug? BTW, I'm using https://spatie.be/docs/laravel-translatable/v6/introduction

Thanks a lot

0 likes
4 replies
Sinnbeck's avatar
Sinnbeck
Best Answer
Level 102

I don't think you can query json columns like that. All laravel does is this query

tag::where([
    'name' => 
        [
            'es' => $tagItem['es'],
            'en' => $tagItem['en']
        ],
])->first();

So just do a manual query and if it's null, create it

1 like
LaraNewDev's avatar

Thanks, I ended up quering like this:

$tag = tag::where('name->es', $tagItem['es'])
                    ->where('name->en', $tagItem['en'])
                    ->get()->first();
                if($tag == null)
                {
					bla bla
shawnyv's avatar

Just an update - this now works in Laravel 11 (not sure when it got added in):

Tag::updateOrCreate(
    [
        'name->es' => $tag_item['es'],
        'name->en' => $tag_item['en']
    ],
    [
        'name' => [
            'es' => $tag_item['es'] . ' updated',
            'en' => $tag_item['en'] . ' updated',
        ]
    ]
);
2 likes

Please or to participate in this conversation.