Removing integer from JSON column using JSON_REMOVE - php

I would like to remove the number 6 from the column access (type json) without knowing its array location.
Example access row 1: [1, 2, 3, 4, 5, 6, 7, 8, 9]
CREATE TABLE example (
id int NOT NULL AUTO_INCREMENT,
access json NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO `example` (`access`) VALUES ('[1, 2, 3, 4, 5, 10, 20, 30]');
SELECT * FROM `example`;
SELECT JSON_SEARCH(`access`, 'one', '30') from `example`;
The JSON_SEARCH doesn't return any results.

You've probably moved on but should anyone else find themselves in the same position as I, trying to search arrays of integers... JSON_SEARCH doesn't support the function.
https://bugs.mysql.com/bug.php?id=79233

Related

Get all rows inside a foreach loop and echo an array result?

I'm trying to get all rows inside a foreach loop but it's not working as it should.
<?php
foreach ($locations_loop as $row):
$lr_id = $row["id"];
$stmtlr = $pdo->prepare("SELECT * FROM locations_rating WHERE l_id = {$lr_id}");
$stmtlr->execute();
$stlr_loop = $stmtlr->fetchAll(PDO::FETCH_ASSOC);
if (empty($stlr_loop)) {
$loc_rate[] = "0";
} else {
foreach($stlr_loop as $rowlr):
$loc_rate[] = $rowlr["stars"];
endforeach;
}
$rating_array = array_values($loc_rate);
$rating_avg = array_sum($rating_array) / count($rating_array);
?>
<?=round($rating_avg, 1);?>
<?php endforeach; ?>
$rating_avg outputs something else every time the script runs. It works fine outside a foreach loop tho. I tried to join the two table but no luck since it only outputs only one row.
I might be thinking too far out of the box, but this is just one technique that occurred to me which will ensure that all location ids will receive an average value in the result set.
Assuming $locations_loop (a poor name for a variable containing array type data, tbh) has the following data:
$locations_loop = [
['id' => 1],
['id' => 2],
['id' => 3],
['id' => 4],
];
And you have a database table with the following schema: (db-fiddle demo)
CREATE TABLE `locations_rating` (
`id` int(11) NOT NULL,
`l_id` int(11) NOT NULL,
`stars` int(11) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `locations_rating` (`id`, `l_id`, `stars`) VALUES
(1, 3, 4),
(2, 2, 2),
(3, 1, 0),
(4, 2, 5),
(5, 3, 2),
(6, 1, 10);
Then you can get all of your data in one trip to the database by creating a "derived table" from your column of id values, then joining the database data to them. Something like this:
SELECT def.l_id,
ROUND(AVG(COALESCE(stars, 0)), 1) avg
FROM (
(SELECT 1 AS l_id)
UNION (SELECT 2)
UNION (SELECT 3)
UNION (SELECT 4)
) AS def
LEFT JOIN locations_rating AS loc ON def.l_id = loc.l_id
GROUP BY def.l_id
To do this with a prepared statement and bound parameters:
$locationIds = array_column($locations_loop, 'id');
$countIds = count($locationIds);
$fabricatedRows = implode(' UNION ', array_fill(0, $countIds, '(SELECT ? AS l_id)'));
$sql = "SELECT derived.l_id,
ROUND(AVG(COALESCE(stars, 0)), 1) avg
($fabricatedRows) AS derived
LEFT JOIN locations_rating as loc ON derived.l_id = loc.l_id
GROUP BY def.l_id";
$stmt = $pdo->prepare($sql);
$stmt->execute($locationIds);
var_export($stmt->fetchAll(PDO::FETCH_ASSOC));
Should output: (I tested this technique to be successful in my local environment)
[
['l_id' => 1, 'avg' => 5.0],
['l_id' => 2, 'avg' => 3.5],
['l_id' => 3, 'avg' => 3.0],
['l_id' => 4, 'avg' => 0.0],
]

Laravel 5.8 update mysql json column cast as array changes data stored format

I have a table with a json column cast as array. The Schema creation has the column defined like this:
$table->json('row_ids');
In my class:
protected $casts = [
'row_ids' => 'array',
];
I generate the data in this array / column by getting every row id from another table like this:
$id_array = DB::table($table->name)->pluck('api_id')->toArray();
TableChannelRow::create([
'table_api_id' => $table->api_id,
'channel_api_id' => $channel->api_id,
'row_ids' => $id_array,
]);
When I dd a collection record I can see the columns in the target table OK, with one of the columns containing an array as expected:
#attributes: array:4 [▼
"api_id" => 2
"table_api_id" => 1
"channel_api_id" => 6
"row_ids" => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, ▶"
]
When I check in MySQLWorkbench the data looks like this:
In another controller I want to add or remove entries from the array in this column like this:
$table_channel_row = TableChannelRow::where('table_api_id', '=', $rowId)
->where('channel_api_id', '=', $channelId)
->first();
$row_ids = $table_channel_row->row_ids;
if ($is_checked == 'yes') {
// Add value to array if it does not already exist
if (!in_array($row_id, $row_ids)) {
array_push($row_ids, $row_id);
}
} else {
// Remove value from array
$row_id_array[] = $row_id;
$row_ids = array_diff($row_ids, $row_id_array);
}
$table_channel_row->update([
'row_ids' => $row_ids,
]);
Now the data in MySQLWorkbench looks like this:
Why does it get stored looking like a PHP array in the first instance, then later on update it gets stored as a json object?
Additionally the remove PHP code is working, yet the add is not, though it does not trigger an exception (you can see the first value is removed in the second image, but I cannot find it in the object in MySQL when I trigger the code to add it)
What did I miss? Thanks!
The reason why it's saving differently is because array_diff returns an associative array whereas your initial data is an indexed array. Take the following for example:
$ids = [1, 2, 3, 4, 5];
$ids2 = [1, 2, 3];
Then if you perform an array_diff($ids, $ids2), it would return the following:
[
3 => 4,
4 => 5
]
So if you want to save as the same format as your initial one, you have to retrieve the values of the array using array_values:
$row_ids = array_values(array_diff($row_ids, $row_id_array));

Laravel: How to get custom sorted eloquent collection using whereIn method

I have an array of product ids against which I need to retrieve the model collection. The array is something like this:
$ids = array(9, 2, 16, 11, 8, 1, 18);
Right now, I'm using the following line of code to get the collection.
$products = Product::whereIn('id', $ids)->get();
But it sorts the products against their ids. such as: 1, 2, 8, 9, 11, 16, 18. What I need is the same order as in the $ids array i.e 9, 2, 16, 11, 8, 1, 18.
What should I do to get the same order as in the array?
Use Field() function of mysql (If you are using mysql database) with DB::raw() of laravel something like
$products = Product::whereIn('id', $ids)
->orderBy(DB::raw("FIELD(id,".join(',',$ids).")"))
->get();
Field() returns the index position of a comma-delimited list
Here's another way to do that.
$ids = array(9, 2, 16, 11, 8, 1, 18);
$products = User::whereIn('id', $ids)->orderByRaw('FIELD(id, '.implode(',', $ids).')')->get();

Combination Generator in PHP

I need to write a script which takes a set of numeric values, for example: "1", "2" and "3" (the total number of values could be limitless)
And return the total of every combination, up to a given total, i.e. 5, therefore the return would look something like:
(1),
(2),
(3),
(1, 1),
(1, 1, 1),
(1, 1, 1, 1),
(1, 1, 1, 1, 1),
(1, 1, 1, 2),
(1, 2, 2)
....
What is the most efficient way to do this in PHP?
Thanks in advance.

Sort items in MySql with dots

How to sort id's widt dot's. I have this table:
1, 1.2, 2, 3, 3.1, 3.2, 4, 5, 100, 101, 200 ...
If we use SELECT * FROM table ORDER BY id ASC it will show:
1, 100, 101, 1.2, 2, 200, 3, 3.1, 3.2, 4, 5 ...
But I need this:
1, 1.2, 2, 3, 3.1, 3.2, 4 ,5, 100, 101, 200 ...
Try this::
SELECT * FROM table ORDER BY CAST(id AS DECIMAL) ASC
other things you can do is make your column in database as FLOAT
and then you order your numbers as you do in your sql without CAST
SELECT * FROM table ORDER BY id ASC
and it will work

Categories