In my emails table, I have a column named To with column-type Json. This is how values are stored:
[
{
"emailAddress": {
"name": "Test",
"address": "test#example.com"
}
},
{
"emailAddress": {
"name": "Test 2",
"address": "test2#example.com"
}
}
]
Now I want a collection of all emails sent to "test#example.com". I tried:
DB::table('emails')->whereJsonContains('to->emailAddress->address', 'test#example.com')->get();
(see https://laravel.com/docs/5.7/queries#json-where-clauses)
but I do not get a match. Is there a better way to search using Laravel (Eloquent)?
In the debugbar, I can see that this query is "translated" as:
select * from `emails` where json_contains(`to`->'$."emailAddress"."address"', '\"test#example.com\"'))
The arrow operator doesn't work in arrays. Use this instead:
DB::table('emails')
->whereJsonContains('to', [['emailAddress' => ['address' => 'test#example.com']]])
->get()
I haven't used the json column but as the documentation refers, the below code should work fine.
DB::table('emails')
->where('to->emailAddresss->address','test#example.com')
->get();
In case to store array in json format. And just have an array list of IDs, I did this.
items is the column name and $item_id is the term I search for
// $item_id = 2
// items = '["2","7","14","1"]'
$menus = Menu::whereJsonContains('items', $item_id)->get();
Checkout the Laravel API docs for the whereJsonContains method
https://laravel.com/api/8.x/Illuminate/Database/Query/Builder.html#method_whereJsonContains
Using Eloquent => Email::where('to->emailAddress->address','test#example.com')->get();
You can use where clause with like condition
DB::table('emails')->where('To','like','%test#example.com%')->get();
Alternatively, if you have Model mapped to emails table names as Email using Eloquent
Email::where('To','like','%test#example.com%')->get();
Related
I am using Laravel (PHP) and MySQL for my backend. I am creating methods for setting and getting information from the database. Those information are being send as a json to the frontend.
I can send table information like:
[
{
"id": 4,
"name": "Max"
},
{
"id": 5,
"name": "Eric"
}
]
For this I am using laravel methods like: DB::table('user')->select('user.id', 'user.name')->get();
However my friend who is doing the frontend want the following json code:
[
{
"id": 4,
"name": "Max"
"specific_user_price":{
"S":5.00,
"M":6.00,
"XL":8.00
}
},
{
"id": 5,
"name": "Eric"
"specific_user_price":{
"S":5.50,
"M":10.00,
"XL":15.00
}
}
]
"specific_user_price is a table and "S", "M", "XL" are columns which have different values depending on the user. I do not know how I can create specific_user_price as an array in a query. I can use group_concat but he needs the json like displayed above.
My idea was to create additional columns in user "size S price", "size M price" and "size XL price". However my friend want those values as an own array group, because some users only habe access to one size, so he would get null values.
Any ideas which method in PHP or Laravel I can use for that? Or is there a MySQL method for creating such thing in a query?
Firstly use Models, way easier to work with out of the box. Define your User model like this, with a relationship for the price.
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function specificUserPrice() {
return $this->hasOne(UserPrice::class);
}
}
You also need to have the UserPrice model defined.
use Illuminate\Database\Eloquent\Model;
class SpecificUserPrice extends Model
{
}
Laravel automatically transforms models, you can get away with the following code in the controller.
public function index()
{
return User::with('specificUserPrice')->get();
}
DB::table('user')->select(['id', 4],['name','max'])->get();
DB::table('user')[0]->get()
This gets you the first element in the array
I'm trying to search database with json contains method of laravel. Here is my JSON of one database line:
{
"row": {
"1": {
"ID":"110555175667"
},
"2": {
"ID":"11023235667"
},
"3": {
"ID":"11001414141667"
},
"4": {
"ID":"11023235667"
},
"5": {
"ID":"1100012222225667"
},
}
}
I want to search ID, but as you see there are numbers as properties.
In example I want to find 11023235667. I've tried it like that:
->whereJsonContains('json', [['row' => ['1' => ['ID' => '11023235667']]]])
But it didn't worked. How can I do it?
EDIT:
I have also tried this:
->whereRaw('JSON_CONTAINS(json, "$.row.*.ID", "11023235667")')
I know the property of row must be JSON array to accomplish to match the id, but it has been set as JSON object
The usage of JSON_CONTAINS() accepts a JSON document as its second argument, not a path.
You could use that path to extract the ID's into an array:
SELECT JSON_EXTRACT(json, '$.row.*.ID') FROM ...
+--------------------------------------------------------------------------------------+
| ["110555175667", "11023235667", "11001414141667", "11023235667", "1100012222225667"] |
+--------------------------------------------------------------------------------------+
Using this, you can search the resulting array:
SELECT ... FROM mytable
WHERE JSON_SEARCH(JSON_EXTRACT(json, '$.row.*.ID'), 'one', '11023235667') IS NOT NULL;
You would need to do this using whereRaw() in Laravel, because Laravel doesn't have a builtin query builder function for this expression.
Tip: As soon as you reference a JSON column in the WHERE clause of an SQL query, your query becomes harder to write, and harder to optimize. This should be a red flag indicating your design is wrong. You would be better off storing data in normal rows and columns, not JSON.
I am building API. I ran into issue when building responses such as this one:
{
"id": 1,
"name": "Some name",
"my_joined_table": {
"joined_table_id": "10",
"some_joined_table_field": "some value"
}
},
Joining tables as described in https://laravel.com/docs/5.2/queries would yield result such as:
{
"id": 1,
"name": "Some name",
"joined_table_id": "10",
"some_joined_table_field": "some value"
},
Instead of using join I could just run two queries, one for main table, second one for secondary and then just append second array to first one and spit JSON response, but it's a lot of queries and appending if list is big!
Example code which yields second result in pseudo-code:
$data = Model::select('id', 'name', 'my_joined_table.id as joined_table_id', 'my_joined_table.some_value some_value')
->leftJoin('my_joined_table', function($join) { //conditions_callback
})->get();
return response()->json($data);
Please advice.
EDIT2:
It seems that I can use with as follows:
$data = Model::with('my_second_table')->first();
return response()->json($data);
It does what I want, only the problem, that I cannot specify fields for both first and second tables using ->first($fields) and->with(['my_second_table' => function ($query) { $query->select('id', 'some_value'); }]) unless I specify primary key of second table in ->first($fields). How do I work around this?
TL;DR; Issue: http://laravel.io/bin/YyVjd
You can probably use Laravel Eloquent relationship to achieve it.
https://laravel.com/docs/5.2/eloquent-relationships#one-to-many
Or you can remap the returned data to a new response object using $appends.
Try something here,
http://laraveldaily.com/why-use-appends-with-accessors-in-eloquent/
This is just some clues and there is a lots work to do.
FYI, you can set $visible in your model to specify which attributes is visible.
I refered to Wordpress' database to create config setting for my app in Laravel. I created a app_settings table with id, setting_name and setting_value as columns to store each config name and value in rows. It works fine but the problem occurs whenever I retrieve or update data.
$appsetting = new AppSetting();
return $appsetting->all();
When I query the database it returns me a json like:
[
{
"id": 37,
"setting_name": "site_name",
"setting_value": "Title",
"created_at": "2015-03-09 10:40:35",
"updated_at": "2015-03-11 03:23:48"
},
{
"id": 38,
"setting_name": "site_url",
"setting_value": "http://localhost:800",
"created_at": "2015-03-09 10:40:35",
"updated_at": "2015-03-11 03:23:48"
},
{
"id": 39,
"setting_name": "site_admin",
"setting_value": "local#host.com",
"created_at": "2015-03-09 10:40:35",
"updated_at": "2015-03-11 03:23:48"
}
]
Case 1:
Whenever I had to use a variable I had to remember the column index to get it's value. Eg. $settings[0]['setting_value'] to retrieve Titleand this make code pretty much static than using something like $settings['site_name'].
Case 2:
If I had to update multiple settings at once, I had to use multiple update commands with where clause.
$appsetting::where('setting_name', '=', 'site_name')->update(['setting_value' => $setting['title']]);
$appsetting::where('setting_name', '=', 'site_url')->update(['setting_value' => $setting['url']]);
$appsetting::where('setting_name', '=', 'site_admin')->update(['setting_value' => $setting['email']]);
What are the best way to update or retrieve rows in database in this case?
I want output like this while using attributes like site_title in rows
[{
"site_title" : "Title",
"site_url" : "http://localhost",
"site_admin" : "local#host"
}]
You have encountered the fundamental problem with using the EAV database structure (although yours may more acurately be describes as Row Modelling) http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model
This type of data structure is never easy to query or update and I would recommend that you drop it and just create a config table with columns for each config var. At some point you are going to have defined all the settings that you need so you can build the table for them. If you later want to add another config setting then just add the column to the table.
That said, if you insist on using the EAV then have your code convert the results into something more usable:
$config = new \stdClass;
foreach($result as $row){
$config->$row['setting_name'] = $row['setting_value'];
}
$title = $config->site_title;
$output = array();
foreach ($settings as $setting) {
$output[] = array($setting['setting_name'] => $setting['setting_value']);
}
return json_encode($output);
I Hope this sample will help you, but i wrote the code in Doctrine DQL:
$query=$this->em->createQuery('UPDATE Alireza\Domain\Entities\Pages_modules u
SET u.Sorder =
WHEN u.R THEN 'Road'
WHEN u.M THEN 'Mountain'
WHEN u.T THEN 'Touring'
WHEN u.S THEN 'Other sale items'
ELSE 'Not for sale'
WHERE u.id IN(1,2,8,9)');
Return $query->getResult ();
this type of queries do not have n+1 problem
In Codeigniter I am creating an array and returning it to the user. I am creating the array like this (result is the return form a DB query):
array("email" => $result)
Right now it outputs:
"email": [
{
"id": "629",
"desc": "0000",
"value_1": "0000",
"value_2": null,
"value_3": null,
"value_4": null,
"privacy": "0"
}
]
So $result is an array that contains a single object. How can I make $result contain just the object instead? Like this:
"email": {
"id": "628",
"desc": "THIS IS IT",
"value_1": "THIS IS IT2",
"value_2": null,
"value_3": null,
"value_4": null,
"privacy": "0"
}
Thankful for all input!
Just use:
array("email" => $result->row());
See the CI documentation on queries and row():
This function returns a single result row. If your query has more than one row, it returns only the first row. The result is returned as an object.
First one is a JSON Object that has a property/member email that is, in turn, a JSON Object that contains properties id, desc etc.
The second one, on the other hand, is a JSON Object that has a property email that is a JSON Array that contains 1 element that has properties id, desc etc.
Basically, if I were to translate the access to the value of value_1 field:
1 object:
obj.email.value_1
2 object:
obj.email[0].value_1
The first defines email as an object.
The second defines email as plain array with one item, and that item is an object by itself.
For example, to access id property using the first form of email you should have:
var id = obj.email.id;
In the second form:
var id = obj.email[0].id;
Edit: answer to your new question "How can I get the second one to look like the first one" - you can't. The second form is defining whole different thing, you just have to change the way you access that email and if always have one item, use email[0] like in the above sample code.