Laravel Chunk Returning Few Data - Laravel - php

I have about 2000 records in my database and i want to fetch them using view into my datatable.
When i run my code, i noticed my database is only showing 166 records. Why is that happening ?
Controller
$chunks = Items::
where('is_active', 1)
->pluck('name','code','barcode','is_active')
->chunk(10);
foreach ($chunks as $key => $chunk) {
$chunks[$key] = array_values($chunk->toArray());
}
Log::info($chunks);
return $chunks;

Your problem is related to the way you retrieve your data:
$chunks = Items::
where('is_active', 1)
->pluck('name','code','barcode','is_active');
Here, you are misusing pluck(). This method returns an array (a Collection in this case but it's the same here) where the first argument is the value and the second argument is the key.
You are passing 4 parameters, the last two are useless.
Here is what's happening:
$chunks = Items::
where('is_active', 1)
->pluck('name','code'); //removed the last two parameters, they are not used
$chunks is a Collection, where the key is the code and the value is the name.
A Collection, like an array, cannot have the same key multiple times. Then, if two users share the same code, the second user will "overwrite" the first one. The third will overwrite the second and so on.
At the end, you'll have a Collection where the number of items will be equal to the number of unique code that are active (where('is_active', 1).
This why it fails.
How to fix this? Use get(), it does exactly what you expected pluck to do:
$chunks = Items::
where('is_active', 1)
->get(['name','code','barcode','is_active']) //be careful, array here
->chunk(10);
foreach ($chunks as $key => $chunk) {
$chunks[$key] = array_values($chunk->toArray());
}
Log::info($chunks);
return $chunks;

Related

Laravel Collections - compare and check how many times a word exits in a collection

i am new to Laravel and i am trying to do the following:
i have 2 Collections: "requirements" and "skills":
$req = collect([
'Installation',
'Konfiguration',
'Automatisierung'
]);
$skills = collect([
'Engineering Team',
'Installation',
'Konfiguration',
'Konfiguration',
'Automatisierung',
'Security',
'Automatisierung',
'Automatisierung',
'Automatisierung'
]);
I am trying the following: I want to take the first item of $req ("Installation") and count how many times it exists in the $skills collection. Then i need to take the second value of the $req collection and do the same thing. At the end i need to have some output like:
Installation exits 2 times
Konfiguration exists 2 times
Automatisierung exists 3 times
all others -> 0 (or even ignoring it)
i thought about iterating with nested for loops and if clauses and so on like "classic" coding, but isnt there something in laravel to make it nicer? I tried like contains and so on but its like "if" clause.
Thanks a lot in advance
You could use countBy of laravel, it counts depending on a function
Learn more about countBy here
This code would return another array with the 3 sentences you've said
$req->map(function($i) use ($skills) {
$count = $skills->countBy(function ($skill) use ($i) {
return $skill == $i;
});
if (isset($count[1])) {
return $i . " exits ". $count[1] ." times";
} else {
return $i . " doesn't exits";
}
});
You can also just do $skills->countBy() that it would return an collection with key beeing the name of the skill and the value beeing the number of times it appears

Need to unset a specific session array

I have set an array to a session variable using key-value pairs, but I need to unset that specific session when I click on the delete button.
This is the code that stores the session variables:
$_SESSION['product'][] = array(
'product_id' => $part_id,
'title' => $title,
'price' => $price,
'default_img' => $default_img,
'quantity' => $quantity);
And here's the code that unsets the session:
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
foreach($_SESSION['product'] as $item) {
if ($_GET["partid"] == $item['product_id']) {
unset($_SESSION["product"]);
}
The problem I'm having is that instead of just unsetting one session instance, it unsets the entire session. I've tried unset($_SESSION["product"][$item]);
You tell the code to unset the whole session, so it does.
Include the key in the foreach and unset the specific key that you need to unset.
foreach($_SESSION['product'] as $key => $item) {
if ($_GET["partid"] == $item['product_id']) {
unset($_SESSION["product"][$key]);
}
}
You could also search for the specific value and skip the whole loop thing.
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
$key = array_search($_GET["partid"], array_column($_SESSION['product'], 'product_id'));
if($key !== false) unset($_SESSION["product"][$key]);
}
Array_search searches for the GET partid and if it's found it returns the key of where it is, else it returns false.
If you have multiple array items that need to be removed the above array_search method will only remove the first.
You can however loop the array_search to get them all.
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
$prodID = array_column($_SESSION['product'], 'product_id'); // creates a flat array that can be searched
while($key = array_search($_GET["partid"], $prodID)){
unset($_SESSION["product"][$key]);
}
}
Here we search to see if there is a matching value, if there is we delete the key, then the while loop searches again.
If a new matching value is forum it's deleted, if not array_search will return false and break the while loop.
A fourth method is to almost keep the code you have as it is, but loop the array by reference with & and unset the item.
foreach($_SESSION['product'] as &$item) { // notice the &
if ($_GET["partid"] == $item['product_id']) {
unset($item); //because we used &, we can now unset $item
}
}
A fifth method is to use array_diff and array_intersect.
This method is the slowest and should not be used on larger arrays, it can be used with very little difference on smaller arrays (less than 50-100 items).
if (isset($_POST['removeItem'])) {
$prodId=$_SESSION['prodItemId'];
$_SESSION['product'] = array_intersect_key($_SESSION['product'], array_diff(array_column($_SESSION['product'], 'product_id'), $_GET["partid"]));
}
In order to explain it I need to explain it in "reverse" order from what you read it since it's nested.
I start with created a flat array with array_column.
This array only contains the productid's.
I use array_diff to return only the items that is not matching $_GET["partid"].
What we get is a flat array with only the productid's. That may sound useless, and it is, but the keys is useful.
The keys match what is in the session array.
So if we use array_intersect_key and use $_SESSION['product'] as the main array and the keys from the array_diff then the output is the items in $_SESSION['product'] that does not match $_GET["partid"].
It's complicated in the background but it's a simple on liner.

Laravel 5: How to put multiple items into the same key in a collection without overriding?

Trying to figure out how to parse a collection and put multiple items into the same key in another collection.
Currently I'm doing this using an array and then I make a collection out of it, but the items inside are not of type Collection, each key is an array and I can't use methods like first() on those arrays. Yes, I can use [0] instead, but I'd prefer to have access to methods available for collections.
$some_array = [];
// Parsing the existing collection using foreach
foreach ($items_collection as $item) {
// Doing some checks
if ($item->some_attribute1 == 1
&& #$item->some_relation->some_attribute2
) {
// Putting the item into the array with a specific dynamic key
$some_array[$item->some_relation->some_attribute2][] = $item->some_relation;
}
else if ($item->some_attribute1 == 0
&& #$item->some_relation->some_attribute3) {
// Putting the item into the array with a specific dynamic key
$some_array[$item->some_relation->some_attribute3][] = $item->some_relation;
}
}
// Defining a new Collection
$new_collection = new Collection();
// Parsing the array of groups of items and putting them in the newly created Collection by their key
foreach ($some_array as $key => $key_items) {
$new_collection->put($key, $key_items);
}
If to make something like this
$some_collection = new Collection();
foreach ($items_collection as $item) {
if ($item->some_attribute1 == 1
&& #$item->some_relation->some_attribute2
) {
$some_collection->put($item->some_relation->some_attribute2, $item->some_relation);
}
else if ($item->some_attribute1 == 0
&& #$item->some_relation->some_attribute3) {
$some_collection->put($item->some_relation->some_attribute3, $item->some_relation);
}
}
then instead of storing all the items in the same key the new items will just override the old ones. Is there a way to put multiple items in the same key using put()?
Thank you in advance!
Seems that the issue was that I wasn't converting the $key_items into a collection in the last foreach.
Now I just used the collect() method on $key_items to make it into a Collection and everything works now.
foreach ($some_array as $key => $key_items) {
$new_collection->put($key, collect($key_items));
}
I hope someone will find this workaround useful until a more elegant solution will be found.

laravel append wheres in a loop to perform AND filtering

I'm trying to build my own dynamic filtering for my Angular App and Laravel 5.1 API using $httpParamSerializer(params); and Laravel whereIns.
My goal is to pass a set of fields and values I want to filter on and drill down the records I need.
I loop through the fields in Laravel and perform whereIns, then group them into an array, removing duplicates. Unfortunately, this acts more as an OR than an AND, as each whereIn does a new search to match.
Frontend Query:
var filters = {
'review[]' : ['no', 'yes'],
'user_id[]' : [1]
};
HTTP URL: "http://dde-api.localhost/1.0/userquestions?review%5B%5D=no&review%5B%5D=yes&user_id%5B%5D=1"
DB:
Laravel:
$results = [];
// Loop through each field (`review`, `users`, etc..), then search thru array of params
foreach ($input as $filter_field => $filters_array) {
if ($this->validField($table, $filter_field)) {
$res = DB::table($table)->whereIn($filter_field, $filters_array)->get();
if (!in_array($res, $results)) {
array_push($results, $res);
}
I need the query to work as a multiple WHERE clause (AND, not OR) which loops through and appends where clauses to each field ($filter_field), then searches for matching field values.
So the result should be all yes and no records for user 1. Since user 1 doesn't have a record with review: yes, it uses the record from user_id: 4. This is bad.
How can I append multiple WHERE statements to one query as I loop through multiple fields?
Use Your loop like this
$dbTbOBJ = \DB::table("table_name")
// Loop through each field (`review`, `users`, etc..), then search thru array of params
foreach ($input as $filter_field => $filters_array) {
$dbTbOBJ->whereIn($filter_field, $filters_array);
}
$results = $dbTbOBJ->get()

Find which keys of separate arrays intersect using a function

Ok so I have two arrays, one is an input array full of data like :
$array1 = ["_token" => "62d46d4h6dfh841df8h", "sku62" => "3e", "name62" => "meh", "sku61" => "3e", "name61" => "mah", "sku64" => "3e", "name64" => "moh"]
The other holds simply id's: $array2 = [64, 74, 61]
edit for clarity: $array1 is a snippet of input from a post request i.e. $array1 = $request->all(); The numbers present within the keys of this array are unique Id's appended on form generation to distinguish between rows with multiple form elements.
Each row has an "update" checkbox also with an appended unique id. When ticked this id shows up in the request e.g. update64.
$array2 was populated by doing a foreach through the request, identifying the update string and isolating the id:
foreach ($array1 as $id => $value) {
$idInt = filter_var($id, FILTER_SANITIZE_NUMBER_INT);
$str = preg_replace('/[0-9]+/', '', $id);
if ($str === "update") {
array_push($array2, $idInt);
}
}
I want a solution that returns the elements from $array1 that have the appended ids found in $array2.
My own attempt looks like this:
$relevant_keys = function($key1, $key2) {
return ((preg_replace('/[0-9]+/', '', $key1) === $key2)) ? 1 : -1;
};
$filtered = array_intersect_ukey($array1, array_flip($array2), $relevant_keys);
However $filtered is returning empty and if I dd($key2) within the function it's not even returning an element from $array2, I get something from $array1 instead so this has left me confused.
Would appreciate any help.
Here's the solution to the exact problem you posted:
$filtered = [];
foreach ($array1 as $key => $value)
{
if ( ! preg_match('/(\d+)$/', $key, $matches)) continue;
if ( ! isset($matches[1]) || ! in_array($matches[1], $array2)) continue;
$filtered[$key] = $value;
}
But I'm not sure you're approaching this correctly. That input looks suspicious.
Are you sure there's no better way to format the request?
I have a few important insights to share based on your coding attempt.
array_intersect_ukey() should be the perfect function call for his task, but alas, it is not. I'll tell you why.
array_intersect_ukey() suffers in the same way as array_intersect_uassoc() and array_uintersect_uassoc() because the internal algorithm will stop looking for additional qualifying keys after it encounters its first one. I first came upon this reality here.
Also, the way that you've declared and used the custom function arguments ($key1 and $key2) indicates that you believe $key1 always relates to the first nominated array and $key2 always relates to the second nominated array. This is not true and I have seen many developers with this same false impression. The truth is that under the hood, the two parameters fed into the custom function may come from either array.
For the reasons in #1, I'll recommend that you shift your focus to array_filter(). By establishing a lookup array containing whitelisted keys and filtering on keys, you can swiftly filter your data. Inside the callback, I am using trim() to remove the letters before the id number at the end. This is just one way of isolating the whole number at the end of each key.
Code: (Demo)
$lookup = array_flip($array2);
var_export(
array_filter(
$array1,
fn($key) => isset($lookup[ltrim($key, 'a..z')]),
ARRAY_FILTER_USE_KEY
)
);
Output:
array (
'sku61' => '3e',
'name61' => 'mah',
'sku64' => '3e',
'name64' => 'moh',
)

Categories