laravel-scout-tntsearch-driver icon indicating copy to clipboard operation
laravel-scout-tntsearch-driver copied to clipboard

Json Data type mb_strtolower() expects parameter 1 to be string, array given

Open AbanoubNassem opened this issue 6 years ago • 4 comments

I'm using JSON data to store my multi-lang properties on the model, now when am trying to import it to TNT it breaks here

public function tokenize($text, $stopwords = [])
   {
>>   $text  = mb_strtolower($text);
       $split = preg_split("/[^\p{L}\p{N}]+/u", $text, -1, PREG_SPLIT_NO_EMPTY);
       return array_diff($split, $stopwords);
   }

so if my json data is $model->title:

{
	"ar": "ماك",
	"en": "Mac"
}

it explodes because text becomes an array

array:2 [
  "ar" => "ماك"
  "en" => "Mac"
]

so I tried to stringify it by doing : $text = is_array($text) ? json_encode($text) : $text;

it did work , but I have lost the capability to search using arabic language! any other way to solve this issue , thanks!

EDIT: to gain the capabilities to search in Arabic back , I used json_encode($result, JSON_UNESCAPED_UNICODE);

but still TNT-Driver doesn't support json/nested/arrays

AbanoubNassem avatar Mar 12 '19 13:03 AbanoubNassem

good

Ezequielcc1 avatar May 17 '19 14:05 Ezequielcc1

but still TNT-Driver doesn't support json/nested/arrays

I also utilize JSON fields in MySQL and the consequent $casts and $appends properties on Eloquent models, so I also just encountered this attempting to index via tntsearch for the first time...

In my case, the fields containing JSON are not immediately critical to the indexing and search functioning... although of course it will be a 'nice-to-have', and not have to be concerned about this issue or conjure work-arounds.

But since I am able to get by without the JSON fields getting indexed, I excluded them from the Searchable Array:

    /**
     * Get the indexable data array for the model.
     * 
     * @return array
     */
    public function toSearchableArray()
    {
        $scanable = $this->toArray(); # dd( $scanable );

        # Exclude JSON fields, as they break tntsearch's index processing :/
        #  => https://github.com/teamtnt/laravel-scout-tntsearch-driver/issues/229
        return Arr::only($scanable, ['id',
            'name', 'nickname',
            'state', 'description'
        ]);
    }

In this case, the text data for nickname is actually stored inside a JSON column, but to ease access to the property for my api endpoint as well as now for tntsearch-indexing purposes, I just expose it with an attribute accessor, like this:

    /**
     * $team->nickname aliases $team->name_mutations->_nick
     */
    public function getNicknameAttribute()
    {
        return $this->name_mutations['_nick'];
    }

... And append that faux-attribute for API responses, with the $appends property:

    protected $appends = ['nickname'];

So, using attribute accessors and the $appends model property to flatten some text from inside a JSON column is one way to work around this problem... feasible probably only when the nested JSON attributes is a small part of what you would like to index.

emjayess avatar May 28 '19 17:05 emjayess

I have a different approach. I save all the translations in the index with different keys.

public function toSearchableArray()
    {
        $array = array(
            'id' => $this->id,
            'name-en' => $this->getTranslation('name', 'en'),
            'name-sv' => $this->getTranslation('name', 'sv'),
        );
        return $array;
    }

tanthammar avatar Jun 12 '19 20:06 tanthammar

Use Spatie/laravel-translatable package instead

nagi1 avatar Apr 19 '21 13:04 nagi1