laravel/scout

attributesToRetrieve: array_flip(): Can only flip string and integer values, entry skipped

pedzed opened this issue ยท 8 comments

pedzed commented

Scout Version

10.2.2

Scout Driver

Meilisearch

Laravel Version

10.14.1

PHP Version

8.2.4

Database Driver & Version

No response

SDK Version

1.2.0

Meilisearch CLI Version

No response

Description

I'm getting the following error:

array_flip(): Can only flip string and integer values, entry skipped

  at vendor/laravel/scout/src/Engines/MeilisearchEngine.php:274

I'm probably doing something wrong, but either way, there is something wrong with the library. Perhaps missing precondition checks?

If the mistake is on my side, then I expect an exception to be thrown with a clear description of what's wrong.

Steps To Reproduce

In MyModel, have something like:

public function toSearchableArray(): array
{
    return [
        'field1' => $this->field1,
        'field2' => $this->field2,
    ];
}

In scout/config.php, have something like:

// ...

'meilisearch' => [
    // ...
    'index-settings' => [
        MyModel::class => [
            'filterableAttributes' => [
                'field1',
                'field2',
            ],
        ],
    ],
],

// ...

Then update those indexes:

artisan scout:sync-index-settings

Finally try searching with:

MyModel::search($query, function (Indexes $meilisearch, string $query, array $options) {
    $options['attributesToRetrieve'] = ['field1', 'field2'];

    return $meilisearch->search($query, $options);
})->first();

Now expect the error:

array_flip(): Can only flip string and integer values, entry skipped

Remove this line and the error goes away:

$options['attributesToRetrieve'] = ['field1', 'field2'];

@pedzed you should add the id (or whatever your unique identifier on the model is) field to the attributesToRetrieve list.

This is a very new feature of the meilisearch SDK, so we didn't find the time to add this yet.

So what happens is, that we pluck the unique identifier in the meilisearch index from the result object. But that exact key is missing in your attributesToRetrieve config and therefore in the result payload of the search request to meilisearch.

Will add an improvement to this

pedzed commented

Seemingly, id gets automatically added to toSearchableArray(), which is what I tried to get rid of with attributesToRetrieve in the first place. But I'm just toying around.

Requiring id and throwing an exception otherwise would suffice.

the unique identifier on the search index needs to be set in the payload. Otherwise meilisearch and laravel scout could never connect a search result with the according dataset in the database.

If you need to send a custom search query to meilisearch and just use the result of the meilisearch payload, you could probably get the meilisearch instance from the service provider and call the meilisearch SDK yourself.

$this->app->singleton(Meilisearch::class, function ($app) {
$config = $app['config']->get('scout.meilisearch');
return new Meilisearch(
$config['host'],
$config['key'],
clientAgents: [sprintf('Meilisearch Laravel Scout (v%s)', Scout::VERSION)],
);
});

pedzed commented

What I'd like to do is search in field1 and field2 only, i.e. with exception of id.

I'm now using

$options['filter'] = 'field1="' . $query . '" OR field2="' . $query . '"';

However, I'm not sure if this is "safe", as one may tamper with the filter like with SQL injection.

@pedzed Ahh..I mixed the attributesToRetrieve functionality with the new searchable fields setting at search time which is coming up in v1.3.0 meilisearch/meilisearch#3772

I think what you are searching for is https://www.meilisearch.com/docs/reference/api/settings#searchable-attributes
The people over at meilisearch discord https://discord.com/invite/meilisearch are always happy to help and give you answers if you need to dig in further

@mmachatschek thanks! Can we close this one?

@driesvints I'll try to send a PR for the attributesToRetrieve which should at least have the scoutkey in the payload.

@pedzed

as info from my PR

Fixes occasions with meilisearch where users can set options on the Builder class like attributesToRetrieve which would restrict the search engine to include the unique identifiers on the search result.

Unfortunately if users customize their search engine calls this issue would still be possible as we have no control over the search result provided by the user.