Image path with two indices

Hello,

Have a Laravel app using VueInstantSearch. The way the images are stored is in a separate table from the Model. So there is a Model table and a Media table. The media table has a foreign key, model_id.

The two indices are model and media.

When I add this line:

<div class="search-panel__results">

    <ais-hits>

        <template slot="item" slot-scope="{ item }">
        <h1>
            <a :href="'/jobs/' + item.slug"> <ais-highlight :hit="item" attribute="jobtitle"></ais-highlight></a>
        </h1>

        <img :hit="item" attribute="model_id" :src=“'/storage/' + item.model_id + '/conversions/' + item.file_name” :hit="item" attribute="model_id" width=200 height=120   alt=""/>

    </template>

</ais-hits>

The item.model_id does not pull from the media table.

Is this possible to set up?

The other approach I thought was to us a regex and strip the
objectID:Spatie\MediaLibrary\Models\Media::9 from the integer and use the php implementation in the VueComponent:

    imageUrl: {!! json_encode($job->getMedia('document')->first()->getUrl('thumbnail')) !!}

Which approach makes the most sense? Thank you ~

Hi @BidBird,

If I understand correctly when referencing the item in your code snippet, this refers to an item in the Media table that is indexed as an Algolia record. This item in the Media table has a foreign key model_id that you would want to access in your Vue template.

To confirm:

  • Are you inquiring, how can you get the model_id attribute indexed to your Algolia record so that it is available for reference?
  • Or are you saying the model_id is successfully indexed to your record but there is an issue in accessing it in the Vue template?

Thank you!

Hi there, thank you. @ajay.david

It’s switched ~ The item = Model. In the case above item.slug = model->slug

So, I’m trying to figure out how to reference the media.model_id (essentially)

In the algolia dashboard both indices are correctly indexed. My trouble is if model = item. How do you display the Media?

Because there are two indices it’s confusing as to how to generate the path. Should the path be generated via php and then displayed via the vue component?

Or should the vue component concatenate the proper keys from the algolia indices ?

This uses the Laravel/MediaLibrary package.

Hi @BidBird,

Thank you for clarifying that:

  • The item = model therefore item.slug = model->slug
  • So you need to understand how to get media.model_id so that you can use that data to build an image path

If you are displaying the model then the best option is to add the attribute model_id to your model record. More on this below.

From the perspective of your database/source-of-truth this might not make sense, but Algolia is different and not your database. You can take advantage of the idea that Algolia records are schemaless. They can have any data you want in the JSON record.

Suggestion:

  • When indexing your model records in Laravel, customize your records and add the model_id so that it is already available in that exact model record:

Hi @ajay.david

You know I was trying that function. Let me play around with it a little more this weekend and I’ll get back to you monday. Might be easier than I’ve made it out to be!

Have a good weekend ~

1 Like

Hi @ajay.david,

I’ve been fussing around with this since we last chatted here.

https://laracasts.com/discuss/channels/site-improvements/withoutsyncingtosearch-algolia-laravel-media-library-thumbnail-image-indexing-issue

I’m wondering, is there a way to delay toSearchableArray()? It all happens so fast the relationship with the media table is not able to sync up in time for the model to save.

The only other idea I’ve come across is making a MySQL view which takes the two models and pulls in the needed data after they are persisted and then the toSearchableArray() is performed on the MySQL view table…

Any thoughts on that?

Thank you ~

/**
     * Get the indexable data array for the model.
     *
     *
     * @return array
     */
    public function toSearchableArray()
    {
//        $job = SlugJob::where('slug', $this->slug)
//            ->first();
//        dd($job);
//        $thumbUrl = $this->getMedia('document')->first()->getUrl('thumbnail');
//        $thumbUrl = optional($this->getMedia('document')->first())->getUrl('thumbnail');
//        dd($thumbUrl);
//        $imageUrl = $job->getMedia('document')->first()->getUrl('thumbnail');;


        return [
// other data...
            'thumbUrl' => $this->thumbUrl ?: '/logos/BidBird-logo.svg',
            'customRanking' => [
                'desc(deadline)'
            ]
        ];
    }

Hello BidBird,

If your relationship between Model and Media is that strong I would suggest doing the initial update in a transaction, that way when the transaction end both table will be up to date and toSearchableArray will have no issue.

https://laravel.com/docs/5.8/database#database-transactions


Other than that you could:

  • use a partialUpdate to update the thumbUrl later but that will increase your operations and not be entirely reliable.

Good morning @samuel.bodin ~ thank you.

I’d like to use algolia for front end search, but getting this thumbnail url seems to be exceptionally tricky when media relates to a model in a relational database.

The trouble is the media cannot be associated with the post until it is created.

// Controller.php

// Validate form

// Store post

// store media with post_id in media table

The above are the basic steps. Is there a way for this to be reliable? I’m a bit reluctant to try a technique you feel is not up to par.

Hi @BidBird, would updating the relationship as discussed here be a workable solution?

Hi @cindy.cullen good morning,

Circled back to this and noticed something awesome.

In email test 2 the path was saved!!!

//algolia index: thumbUrl: "/storage/70/conversions/5e6a63288528b_peter_bidbird_demo-thumbnail.jpg"

    /**
     * Get the indexable data array for the model.
     *
     *
     * @return array
     */
    public function toSearchableArray()
    {
...
$thumbUrl = optional($this->getMedia('document')->first())->getUrl('thumbnail');
 ...
return [
...
'thumbUrl' => $thumbUrl ?: '/logos/BidBird-logo.svg',
...
];

However, it’s not reliable as you can see in the screenshot.

Is it possible to stall the $thumbUrl variable while it’s saved on the server and then proceed with indexing the array?

Thank you ~ getting close!

Hi @BidBird, If there is some way to choose the name/url for your media, you could go ahead an pre-populate that url in your Algolia index and not have to wait for the image to upload.

I’m not sure it would apply to your use case, but you may also look into the wait method.

@cindy.cullen Why is programming so easy to fix when you know the tool?

$thumbUrl = optional($this->getMedia('document')->first())->getUrl('thumbnail')->wait(); 

That’s all I did!

I gave it a shot without an image and it pulled the default logo. So…it seems its working!

Thank you ~

@cindy.cullen well, not sure what happened that allowed the method to work the other day. However, after coming back to the toSearchableArray() I found wait() delivers:

Call to a member function wait() on string

so, it does not help in this case… if you have any further ideas I’d love to hear. Will keep working at this…

Thank you,
T

Hi there, @samuel.bodin

I’m really struggling on this implementation.

Took another look at your DB::transaction idea. I’m now sure how you’d make a transaction over two different models. If I understand right, in order to use a transaction models need to be created before a transaction.

e.g.

	// Create a new job using request data
	$job = SlugJob::create([
            'jobtitle' => request('jobtitle'),
...//other fields
        ]);

//this is where toSearchableArray() is being fired - sometimes media path is included, as mentioned above most other times it's not

        // Store media based on just created job
        foreach ($request->input('document', []) as $file) {
            $job->addMedia(storage_path('medialibrary/temp/' . $file))
                ->preservingOriginal()
                ->toMediaCollection('document', 'media');
        }

        flash('Thank you for creating a job on BidBird.')->success();

I was running through this: https://www.algolia.com/doc/framework-integration/laravel/advanced-use-cases/multiple-models-in-one-index/?language=php

Am I correct this above link does not work with VueInstantSearch?

I never used transaction models before, so I am not able to help you there.

Concerning the “Multiple models in one index” should work as normal with VueInstantSearch. You just need to specify the aggregator index, as the index of VueInstantSearch.

Thanks,