I have a simple query in my model to get data. Now I want to search with companyname.My query code:
$searchablePost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->whereIn('status',$is_or_active)
->whereIn('product_id', $userApprovalProductIDs)
->whereIn('demand_or_supply', $is_demand_supply)
->offset($offset)->limit($limit)
->orderBy('id','desc');
Now, I got 6 rows in this 6 rows I want to filter data with companyname which i get with comma separated abcCompany,indCompany.
array:2 [
0 => "abccompany"
1 => "indcompany"
]
What I try :
if($companyname !="") {
$companyDetail = Explode(',',$companyname);
$searchablePost->whereHas('user.userDetails', function ($query) use ($companyDetail) {
$i=1;
foreach ($companyDetail as $search_with_compayname) {
if(count($companyDetail)>0 && $i==1) {
$query->where('company','LIKE',"%{$search_with_compayname}%");
} else {
$query->orWhere('company','LIKE',"%{$search_with_compayname}%");
}
$i++;
}
});
}
Is it good or is there any other way to good search ?
If you want to search a CSV list of company names, MySQL makes available a function FIND_IN_SET. I think you can just add a whereRaw clause to your current Laravel query:
$searchablePost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->whereIn('status', $is_or_active)
->whereIn('product_id', $userApprovalProductIDs)
->whereIn('demand_or_supply', $is_demand_supply)
->whereRaw('FIND_IN_SET(company, ?) > 0', [$search_with_compayname])
->offset($offset)
->limit($limit)
->orderBy('id', 'desc');
While the above may work, the best long term approach is to avoid CSV and other unnormalized data in your database. Ideally, you would have a table containing the list of company names, with one name on each record. Then, you could join or use an EXISTS query to answer your question.
Related
I have a model that has a field type which consists of several words. The string looks like this: modern premium hot.
How to get relevant results if I want to filter it with an array like this one:
$filter = [0 => 'modern', 1 => 'hot'];
$search = implode(' ', $filter);
$results = Model::where('type', $search)->get();
The above example will not return anything because it will try to match modern premium hot with modern hot and its not the same, but how to get all relevant results that contain the words modern and hot at the same time in the type fields?
In other words how to get all results that have all elements of the array in the type field, which is a string?
Maybe you need a fulltext service like Elastic Search or Algolia, or even look at fulltext search on your database engine (assuming MySQL, check this link).
But if you really need to move on as it is going, you may try something like that:
$query = Model::query();
foreach ($filter as $term) {
$query->orWhere('type', 'LIKE', "%{$term}%");
}
$results = $query->get();
You use orWhere()
$filter = [0 => 'modern', 1 => 'hot'];
$query= Model::query();
foreach($filter as $term) {
$query->orWhere('type', $term);
}
$results = $query->get();
if you have other where() in your query, use this
$filter = [0 => 'modern', 1 => 'hot'];
$results = Model::where(function($query) use($filter) {
foreach($filter as $term) {
$query->orWhere('type', $term);
}
})
//->where(....)
->get();
I am using laravel eager loading to load data on the jquery datatables. My code looks like:
$columns = array(
0 => 'company_name',
1 => 'property_name',
2 => 'amenity_review',
3 => 'pricing_review',
4 => 'sqft_offset_review',
5 => 'created_at',
6 => 'last_uploaded_at'
);
$totalData = Property::count();
$limit = $request->input('length');
$start = $request->input('start');
$order = $columns[$request->input('order.0.column')];
$dir = $request->input('order.0.dir');
$query = Property::with(['company','notices']);
$company_search = $request->columns[0]['search']['value'];
if(!empty($company_search)){
$query->whereHas('company', function ($query) use($company_search) {
$query->where('name','like',$company_search.'%');
});
}
$property_search = $request->columns[1]['search']['value'];
if(!empty($property_search)){
$query->where('properties.property_name','like',$property_search.'%');
}
if(!Auth::user()->hasRole('superAdmin')) {
$query->where('company_id',Auth::user()->company_id);
}
$query->orderBy($order,$dir);
if($limit != '-1'){
$records = $query->offset($start)->limit($limit);
}
$records = $query->get();
With this method I received error: Column not found: 1054 Unknown column 'company_name' in 'order clause' .
Next, I tried with following order condition:
if($order == 'company_name'){
$query->orderBy('company.name',$dir);
}else{
$query->orderBy($order,$dir);
}
However, it also returns similar error: Column not found: 1054 Unknown column 'company.name' in 'order clause'
Next, I tried with whereHas condition:
if($order == 'company_name'){
$order = 'name';
$query->whereHas('company', function ($query) use($order,$dir) {
$query->orderBy($order,$dir);
});
}else{
$query->orderBy($order,$dir);
}
But, in this case also, same issue.
For other table, I have handled this type of situation using DB query, however, in this particular case I need the notices as the nested results because I have looped it on the frontend. So, I need to go through eloquent.
Also, I have seen other's answer where people have suggested to order directly in model like:
public function company()
{
return $this->belongsTo('App\Models\Company')->orderBy('name');
}
But, I don't want to order direclty on model because I don't want it to be ordered by name everytime. I want to leave it to default.
Also, on some other scenario, I saw people using join combining with, but I am not really impressed with using both join and with to load the same model.
What is the best way to solve my problem?
I have table like: companies: id, name, properties: id, property_name, company_id, notices: title, slug, body, property_id
The issue here is that the Property::with(['company','notices']); will not join the companies or notices tables, but only fetch the data and attach it to the resulting Collection. Therefore, neither of the tables are part of the SQL query issued and so you cannot order it by any field in those tables.
What Property::with(['company', 'notices'])->get() does is basically issue three queries (depending on your relation setup and scopes, it might be different queries):
SELECT * FROM properties ...
SELECT * FROM companies WHERE properties.id in (...)
SELECT * FROM notices WHERE properties.id in (...)
What you tried in the sample code above is to add an ORDER BY company_name or later an ORDER BY companies.name to the first query. The query scope knows no company_name column within the properties table of course and no companies table to look for the name column. company.name will not work either because there is no company table, and even if there was one, it would not have been joined in the first query either.
The best solution for you from my point of view would be to sort the result Collection instead of ordering via SQL by replacing $records = $query->get(); with $records = $query->get()->sortBy($order, $dir);, which is the most flexible way for your task.
For that to work, you would have to replace 'company_name' with 'company.name' in your $columns array.
The only other option I see is to ->join('companies', 'companies.id', 'properties.company_id'), which will join the companies table to the first query.
Putting it all together
So, given that the rest of your code works as it should, this should do it:
$columns = [
'company.name',
'property_name',
'amenity_review',
'pricing_review',
'sqft_offset_review',
'created_at',
'last_uploaded_at',
];
$totalData = Property::count();
$limit = $request->input('length');
$start = $request->input('start');
$order = $columns[$request->input('order.0.column')];
$dir = $request->input('order.0.dir');
$query = Property::with(['company', 'notices']);
$company_search = $request->columns[0]['search']['value'];
$property_search = $request->columns[1]['search']['value'];
if (!empty($company_search)) {
$query->whereHas(
'company', function ($query) use ($company_search) {
$query->where('name', 'like', $company_search . '%');
});
}
if (!empty($property_search)) {
$query->where('properties.property_name', 'like', $property_search . '%');
}
if (!Auth::user()->hasRole('superAdmin')) {
$query->where('company_id', Auth::user()->company_id);
}
if ($limit != '-1') {
$records = $query->offset($start)->limit($limit);
}
$records = $query->get()->sortBy($order, $dir);
Say I have 2 models, Category and POI where 1 Category can have many POIs.
$categoryDetails = Category::with([
'pois' => function ($query) {
$query->where('is_poi_enabled', true);
},
])->findOrFail($id);
The above query returns results from the specific Category as well as its POIs.
However, with the query below:
$query->select('id', 'name')->where('is_poi_enabled', true);
The POIs become empty in the collection.
Any idea why this is happening? When added a select clause to the Eloquent ORM?
While doing a select it's required to fetch the Relationship local or Primary key.
For an example POIs table contains category_id then it's required to select it
Try this:
$categoryDetails = Category::with([
'pois' => function ($query) {
$query->select(['id', 'category_id', 'is_poi_enabled'])
->where('is_poi_enabled', true);
},
])->findOrFail($id);
Good luck!
I have following tables in my DB:
TABLE_PRODUCTS
id
name
TABLE_VARIANTS
id
product_id
sku
TABLE_VARIANTS_PROPERTIES
id
variant_id
property_value_id
I'm trying to build query for filtering products. Let's say I want to show only that products which have variants with property_value_id=1 and property_value_id=2
Relations: PRODUCTS -> hasMany -> VARIANTS -> hasMany -> VARIANTS_PROPERTIES.
Any ideas?
UPDATE:
I used Alexandr Peters answer. Here is my code:
$query->whereHas('variants.properties.propertiesValues', function ($query) use ($variants) {
$query->whereIn('value', $variants);
});
To be more specific I have one more table in my query which I didn't specify before. This query works but not as expected. What I want to do is:
Get all PRODUCTS which have PRODUCTS_VARIANTS which have PRODUCTS_VARIANTS_PROPERTIES which have PRODUCTS_PROPERTIES_VALUES as active filter (VARIANTS). I know all variants - I'm using cartesian product for this.
So for example I need to get all products which have variants which have all values from variant in filter. This query works only if there are variants only with 1 value. How can I solve this? I'm trying with foreach($variants as ...) but no luck. Still not working 100% as expected.
TABLES:
TABLE_PRODUCTS
id
name
TABLE_PRODUCTS_VARIANTS
id
product_id
sku
TABLE_PRODUCTS_VARIANTS_PROPERTIES
id
variant_id
property_value_id
TABLE_PRODUCTS_PROPERTIES_VALUES
id
value
All possible variants from active filter are in nested array for example I have active filter with color BLACK and RED and size filter XS:
[
0 => [
0 => Black
1 => XS
]
1 => [
0 => Red
1 => XS
]
]
I need to check values from VARIANTS array in last table TABLE_PRODUCTS_PROPERTIES_VALUES in column value. But it needs to have both values (Black & XS)
Any ideas?
UPDATE - SOLVED
Ok I finally solved it. Here is my code:
$query->whereHas('variants', function ($query) use ($variants) {
$i = 1;
foreach($variants as $variant)
{
if($i == 1) {
$query->whereHas('properties', function($query) use ($variant) {
$query->whereHas('propertiesValues', function($query) use ($variant) {
$query->whereIn('value', $variant);
});
}, '=', count($variant));
} else {
$query->orWhereHas('properties', function($query) use ($variant) {
$query->whereHas('propertiesValues', function($query) use ($variant) {
$query->whereIn('value', $variant);
});
}, '=', count($variant));
}
$i++;
}
});
Any ideas how to make it less complicated? :)
Nested has or whereHas statements may also be constructed using "dot" notation. For example, you may retrieve all posts that have at least one comment and vote. So if you want to query nested variants_properties from products you have to put it with dots 'relation1.relation2' in whereHas
$ids = [1,2];
$products = Product::whereHas('variants.variants_properties', function ($query) use ($ids) {
$query->whereIn('property_value_id', $ids);
})->get();
I am trying to learn whether or not there is a simple way to pass a variable number of parameters to a query in Eloquent, hopefully using an array.
From what I can find, there doesn't seem to be a way to do this without looping through the Input to see what was set in the request.
Examples here: Laravel Eloquent search two optional fields
This would work, but feels non-Laravel to me in its complexity/inelegance.
Here is where I am, and this may not be possible, just hoping someone else has solved a similar issue:
$where = array("user_id" => 123, "status" => 0, "something else" => "some value");
$orders = Order::where($where)->get()->toArray();
return Response::json(array(
'orders' => $orders
),
200
);
That returns an error of course strtolower() expects parameter 1 to be string, array given.
Is this possible?
Order::where actually returns an instance of query builder, so this is probably easier than you thought. If you just want to grab that instance of query builder and "build" your query one where() at a time you can get it like this:
$qb = (new Order)->newQuery();
foreach ($searchParams as $k => $v) {
$qb->where($k, $v);
}
return $qb->get(); // <-- fetch your results
If you ever want to see what query builder is doing you can also execute that get() and shortly after:
dd(\DB::getQueryLog());
That will show you what the resulting query looks like; this can be very useful when playing with Eloquent.
You can try this:
Method 1:
If you have one optional search parameter received in input
$orders = Order::select('order_id','order_value',...other columns);
if($request->has(user_id)) {
$orders->where('orders.user_id','=',$request->user_id);
}
//considering something_else as a substring that needs to be searched in orders table
if($request->has('something_else')) {
$orders->where('orders.column_name', 'LIKE', '%'.$request->something_else.'%');
}
$orders->paginate(10);
Method 2:
If you have multiple optional parameters in input
$orders = Order::select('columns');
foreach($input_parameters as $key => $value) {
//this will return results for column_name=value
$orders->where($key, $value);//key should be same as the column_name
//if you need to make some comparison
$orders->where($key, '>=', $value);//key should be same as the column_name
}
return $orders->paginate(15);