ElasticSearch in e-commerce: multiple categories for a product - elasticsearch

How do you index products like that in ElasticSearch? We've separated all documents based on the attributes (colour, brand, size, whatever users input), but all of them belong to a set of categories. May be one, may be 15.
[0] => Array
(
[product_id] => 123456
[product_name] => Shirt 1
[filter_name] => Colour
[filter_value] => Blue
[product_parent_id] => 111111
[product_has_discount] => 0
[product_price] => 19.99
[product_stock] => 1
)
[1] => Array
(
[product_id] => 123457
[product_name] => Shirt 1
[filter_name] => Colour
[filter_value] => Red
[product_parent_id] => 111111
[product_has_discount] => 0
[product_price] => 19.99
[product_stock] => 1
)
How would we tag categories into this? Would it be so simple as saying
[product_categories] => ;4750;4834;4835;4836;
And then querying ElasticSearch with match against category with the value ;4836;? Is that possible? Recommended?

You can define product_categories as integer in your mapping and pass in the category values as array like
[product_categories] => array(4750,4834,4835,4836)
EDIT: You read more about mapping here. A more specific to mapping an array type.
Once your data is indexed like that you can query, filter, aggregate on the field product_categories easily in all combinations.
for example to match products in category 4750 or 4750:
{
"filter": {
"terms": {
"product_categories": [
4750,
4750
]
}
}
}

Related

How to filter using eloquent using distinct?

Would like for some help. Currently I have a table with multiple records.
Columns have is : id, identifier, price
I would like to write a query which I'm able to get the unique identifier with the highest price only.
I would like the collection to be
[
[
'id' => 5,
'identifier' => 1001
'price' => 50
],
[
'id' => 7
'identifier' => 1002,
'price' => 35
]
]
the first array id is 5 because from the identifier 1001 the highest price is 50 and the id is 5 and second array id is 7 because identifier 1002 highest price is 35
$maxPrices = Model::select(DB::raw('max(price)'))
->groupBy('identifier')->get();
query result: [50, 35]
Model::select()->whereIn('price',$maxPrices)->orderBy('price', 'desc')->get()
query result
[
[
'id' => 5,
'identifier' => 1001
'price' => 50
],
[
'id' => 7
'identifier' => 1002,
'price' => 35
]
]
Use this to get all distinct identifiers with max price (edit table):
$products = DB::table('tbl_products')->groupBy('identifier')->get(['identifier', DB::raw('MAX(price) as price')]);
Hi guys found a better solution. Read on DB view table. This function will create a virtual table with the value wanted and in laravel you can create a model to reference that virtual table and do eloquent query on it.

how to sort data in Laravel Eloquent query, based on a specific field

I have this Eloquent query:
$events = Product::forCard()->latest()->take(setting('storefront_recent_products_section_total_products', 10))->get();
I want to sort this record in ascending order by start_event. I tried to do this, but I have some issues because data come from multiple tables.
Array
(
[0] => Array
(
[price] => Modules\Support\Money Object
(
[amount:Modules\Support\Money:private] =>
[currency:Modules\Support\Money:private] => USD
)
[special_price] =>
[selling_price] => Modules\Support\Money Object
(
[amount:Modules\Support\Money:private] =>
[currency:Modules\Support\Money:private] => USD
)
[special_price_start] =>
[special_price_end] =>
[options_count] => 0
[id] => 40
[slug] => -YvHm5m1m
[in_stock] => 1
[new_from] =>
[new_to] =>
[name] => Race4
[description] =>
[organizer] =>
[short_description] =>
[address] =>
[city] => vehari
[state] => pakistan
[zip_code] =>
[lat] =>
[lng] =>
[start_event] => 2020-01-13 00:00:00
[end_event] =>
[translations] => Array
(
[0] => Array
(
[id] => 33
[product_id] => 40
[locale] => en
[name] => Race4
[city] => vehari
[state] => pakistan
[start_event] => 2020-01-13 00:00:00
)
)
[files] => Array
(
)
)
You should be able to order is ascending something similiar to this:
$events = Product::forCard()->latest()
->take(setting('storefront_recent_products_section_total_products', 10))
->orderBy('start_event', 'asc');
Basically you can tell using the method orderBy() which column shall be used to order and the type of ordering, in this case ascending.
Laravel makes it easy and absolutely no brainer to sort data.
$events = Product::forCard()->latest()->take(setting('storefront_recent_products_section_total_products', 10))
->orderBy('start_event')->get();
Where start_event is the column you want t use in sorting.
There is a better approach, as the above code will automatically sort the returned data in an ascending order, but you can explicitly tell it what to do.
Just modify the last part of the code with:
orderBy('start_event', 'ASC')->get(); /** If you want Ascending OR; **/
orderBy('start_event', 'DESC')->get(); /** If you want Descending. **/

how to submit bulk record of following array using eloquent or query builder

I have sale product form where user will receive cash against product at cash counter, and products could be many. How to submit that record at once using eloquent and query builder with following array pattern
Array
(
[_token] => jsVji1V6cTt5XmD2XgWyA7GEH5lvPlYbYWtUPIrt
[productId] => Array
(
[0] => 1
[1] => 2
)
[quantity] => Array
(
[0] => 1
[1] => 1
)
[amountReceived] => Array
(
[0] => 100
[1] => 500
)
[deliveryLocation] => Array
(
[0] => london
[1] => new york
)
)
Simply create an associative array like below and insert:
for($i=0;$i<count(data['productId']);$i++){
$temp[]=array('productId'=>$data['productId'][$i], 'Quantity'=>$data['Quantity'][$i],'amountReceived'=>$data['amountReceived'][$i]);
}
Model::insert($temp);
Docs are here

Elasticsearch return distinct property values

I have collection of Products with property Brand and 2 unique values:
"Super brand A"
"Super brand B"
ES query
var response = new ElasticClient().Search<DTO>(s => s
.Index("index")
.Type("type")
.Aggregations(a => a
.Terms("unique", t => t
.Field(f => f.Brand)
//.Field(f => f.Brand.Suffix("keyword"))
.Size(1000)
)
)
);
var brands = (((BucketAggregate)response.Aggregations.First().Value).Items).Cast<KeyedBucket<Object>>().Select(x => x.Key).ToList();
ES returns 4 invalid values
"Super"
"brand"
"A"
"B"
I've tried to force full property match by adding .Suffix("keyword") to field but then it returns empty list. How can I get 2 distinct values?

Laravel eager loading returns all results when querying realtionship

I want to get products with a seri name contains a certain word. However it returns all products. Matching serie name condition appears to be array under each related product; for the rest of products it is just a blank "serie" key.
$products=Product::with(array(
'serie'=>function($query)
{
$query->where('name','like','%unky%');
}))
->get()->toArray();
and array returned is like
[0] => Array
(
[id] => 1
[updated_at] => 2014-02-14 22:26:04
[created_at] => 0000-00-00 00:00:00
[brand_id] => 1
[cat_id] => 1
[serie_id] => 1
[devices_ids] => 1
[color_code] => #BEB991
[barcode] => 8699131462430
[title] => Funky Charlie iPhone 5/5S Kılıfı
[desc] => Sert 6 gr
[price] => 29.90
[serie] => Array
(
[id] => 1
[updated_at] => 2014-02-14 22:18:31
[created_at] => 0000-00-00 00:00:00
[name] => Funky
)
)
[1] => Array
(........
[5] => Array
(
[id] => 6
[updated_at] => 2014-02-14 22:46:10
[created_at] => 0000-00-00 00:00:00
[brand_id] => 1
[cat_id] => 1
[serie_id] => 2
[devices_ids] => 1
[color_code] => red
[barcode] => 8699131462546
[title] => Bonjour Kırmızı iPhone 5/5S Kılıfı
[desc] => Sert 6 gr
[price] => 24.90
[serie] =>
As you can see serie key is empty.
What i want is only to bring products with matching serie name and does not bring products like with id"5".
What i am doing wrong?
Thanks
I think that instead of using Model::with(), you want to instead filter the Model, based on the related model, so you should use Model::whereHas()
$products = Product::whereHas('serie', function($query)
{
$query->where('name','like','%unky%');
})->get()->toArray();
Eager loading constraints do not put a constraint on the results of the model - it constraints the related model. In your case, you get all Products. But if you try to access the Series of a Product, you will only get those Series that are true to your condition.
If you need to access the Series too and do not only need the Products, I would make the query like this:
$products=Product::with(array(
'serie'=>function($query)
{
$query->where('name','like','%unky%');
}))
->whereHas('serie', function($query) {
$query->where('name','like','%unky%');
})
->get()->toArray();
In this case, you get only the Products that are linked to a Serie whose name is like %unky% and you get only the related Series that hold to the same condition.
To sum this up: whereHas restricts the list of Products based on the condition, whereas the Eager Loading constraint restricts only the list of Series for each Product.

Resources