Importing info from two tables using scout:import

Im trying to query multiple databases with the following structure ->

Table 1 -> products:

Model:

public function productdetails()
{
    return $this->hasMany('App\Models\ProductDetails', 'productId', 'id');
}


Table 2 -> products_details:

Model:

public function product()
{
    return $this->hasOne('App\Models\Product', 'productSku', 'productId');
}

Using php artisan scout:import “App\Models\Product”:

gives result:

Illuminate\Database\Eloquent\Collection {#1787
     all: [
       App\Models\Product {#1779
         id: 1,
         productName: "Samsung - Galaxy Core Prime 4G",
         productSku: "3953367",
         more info...
         created_at: "2017-04-08 18:28:46",
         updated_at: "2017-04-08 18:28:46",
         deleted_at: null,
       },
     ],
   }

My question is, how can I upload results into Algolia but retrieving products + products details ( to receive all name/value associated to productId) ?

Illuminate\Database\Eloquent\Collection {#1787
     all: [
       App\Models\Product {#1779
         id: 1,
         productName: "Samsung - Galaxy Core Prime 4G",
         productSku: "3953367",
         more info...
         created_at: "2017-04-08 18:28:46",
         updated_at: "2017-04-08 18:28:46",
         deleted_at: null,
         productId: 3953367,
         name: "Operating System",
         value: "Android 4.4 KitKat",
       },
     ],
   }

including foreach value like this example:

productId: 3953367,
name: “Operating System”,
value: “Android 4.4 KitKat”,
name: “”,
value: “”,

1 Like

Hi @siherrera,

Few questions here:

  1. do you already index the “product details” as part of the “products” index?
  2. how do you plan to use this, could you share the code snippet where you use the actual results to illustrate your problem?
  3. do you use the “toSearchableArray” method to push your relations?

Here are some fresh links that might help:

Looking forward for your answer.

Hi @rayrutjes,

  1. Im trying to do so. I can do that on laravel.tinker eg: https://stackoverflow.com/questions/45406730/tinker-querying-multiple-databases-to-receive-all-name-value-associated-instead (despite only one pair of product details is returning) . Honestly I dont know how to invoke that code using php artisan scout:import “App\Models\Product::eg:function”:

  2. its a new implementation. My idea is to use it like
    App\Models\Product {#1779
    id: 1,
    productName: “Samsung - Galaxy Core Prime 4G”,
    productSku: “3953367”,
    more info…
    created_at: “2017-04-08 18:28:46”,
    updated_at: “2017-04-08 18:28:46”,
    deleted_at: null,
    productId: 3953367,
    facets:{
    name: “Operating System”,
    value: “Android 4.4 KitKat”,
    name: “x1.1”,
    value: “x1.2”,
    name: “x2.1”,
    value: “x2.2”,
    },
    },

  3. Im planning to use Tosearch… when I retrieve the correct values in order to create a more suitable schema for my needs, similar to the schema your company used with demo instant-search using bestbuy products data.

hope it helps these info.
thank you, best regards!!

I think you only to use the toSearchableArray() method. If understood correctly you should get something like.

public function toSearchableArray()
{
    $product = $this->toArray();

    $details = collect($this->productDetails)
        ->mapWithKeys(function ($item) {
            return [$item['name'] => $item['value']];
        })
        ->all();

    $product['os'] = $details['os'];
    $product['xx'] = $details['xx'];

    return $product;
}

Please let me know if that answers your question.

Thank you so much Julien, working on it to see how it works!

1 Like

@julienbourdeau finally I used the following schema:

public function toSearchableArray()
{

$array = $this->toArray();

$array[‘productdetails’] = $this->productdetails->map(function ($data) {
return $data[‘name’];
})->toArray();
return $array;
}

despite now I have to map correctly in order to import to algolia for better results, all the information of products and productsdetails were included. Thank you so much.

one more question please, :

It’ s possible to limite inside toSearchableArray() function the amount of results retrieved. Im reaching the max amount of records in my free plan and in order to test prior to move to a paid plan it would be great for me to find a way to limit the amount of values retrieved buy $this->toArray() on each model.

As an example, I tried $product = $this->take(5)->toArray() but an error appeared:

[BadMethodCallException]
Call to undefined method Illuminate\Database\Query\Builder::toArray()

thank you so much!.
Sebastian.

Hi Sebastian,

Algolia only cares about the number of records and their size. The number of attribute is not important.

Are your record too big (over 10KB) or you have to many?

If you want to index less records, I think the best way would be to create a custom command, based on the original one.

And replace $model::makeAllSearchable() by something like $model::take(1000)->searchable();. I haven’t tried it tho.

Please let me know if it worked.

Hi Julien,

Currently I have 16k in my product table. Checking toSearchableArray the following code is displayed:

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

in my code for model product I used : $product = $this->toArray();

With $product = $this->toArray(); all records of the model are retrieved, my main question was referred to a way to override $this->toArray() in a way to receive less results.

eg: trying $this->take(2)->toArray(); gives error.

thank you!.

There is a misunderstanding here. The toSearchableArray() will not return an array of the 16k product. It transforms one product into an array, and it will be called 16K times.

If you reduce the of entry at this level, you will reduce the number of attributes of each product but you will still have 16K records

perfect!. now I understand. thank you!.

1 Like