append to a field of array with eloquent - laravel

I have an application with laravel and mongodb. With elequent iam trying to append a new value to an array stored in a field.
So this is an example of a document. Iam trying to append a new value to the projects field.
{
"_id":{
"$oid":"5f80513714450000a6007c90"
},
"organization_id":"5f80304214450000a6007c81",
"user_id":"5f80513714450000a6007c8f",
"status":true,
"role_id":"5c148783fe412ba8333074ec",
"company_id":"5f80511f14450000a6007c8e",
"updated_at":{
"$date":"2020-11-09T18:42:03.000Z"
},
"created_at":{
"$date":"2020-10-09T12:01:59.000Z"
},
"projects":[
"5fa33513416100008d0070ba",
"5f80429814450000a6007c85",
"5f80436714450000a6007c86"
]
}
in my model i have created this method
public function push_user_projects($data, $where_data) {
return UserAccountsModel::where($where_data)->put($data);
}
The where_data works good. The method finds the correct documents to update.
But what doesent work is the pushing part. The following is what i put into data parameter
$data = array(
'projects' => array(
$projectData["_id"]
)
);
And when i se the result a complete new array has updated the projects field with the new value. But i want to append the value to the existing array. Can someopne help me?

To push another element into your data variable under 'projects'
$data['projects'][] = $projectData["_id"];

Related

How to convert lavavel collection to square bracket collection

I have laravel livewire collection as below.
[
{
"date":"2021.09.01-0:00",
"open":110.177,
"close":110.175,
"low":110.172,
"high":110.18
},
{
"date":"2021.09.01-0:01",
"open":110.175,
"close":110.171,
"low":110.169,
"high":110.175
},
{
"date":"2021.09.01-0:02",
"open":110.171,
"close":110.173,
"low":110.17,
"high":110.176
}
]
I would like to convert them into form of square bracket collection without key name as below .
$data = [
['2021.09.01-0:00',110.177,110.175,110.172,110.18],
['2021.09.01-0:01',110.175,110.171,110.169,110.175],
['2021.09.01-0:02',110.171,110.173,110.17,110.176]
];
Any advice or guidance on this would be greatly appreciated, Thanks.
You can use collection map method:
The map method iterates through the collection and passes each value to the given callback. The callback is free to modify the item and return it
https://laravel.com/docs/8.x/collections#method-map
$expectData = $collection->map(fn($item) => [$item-> date, $item->open,...])
I am not sure what the original data is but you can map over the collection and pull the values; if Eloquent Models:
$data->map(fn ($v) => array_values($v->toArray()))
Would depend upon how you got that original Collection for how it would end up in this scenario.
If you need to restrict what attributes and the order of them returned you can use only on the model:
fn ($v) => array_values($v->only(['date', ...]))

Laravel Scout/Meilisearch - filter by a non-searchable column

I want to make it so that I can filter results based on a column that isn't searchable with Meilisearch and Laravel scout.
So imagine a "Comment" table, with the following searchable columns:
public function toSearchableArray() {
$array = Arr::only(
$this->toArray(),
['id','title', 'link', 'raw_text', 'subchan', 'nsfw']
);
return $array;
}
But only get results past a certain date:
Comment::search($query, ['filters' => 'created_at > 795484800'])
To do this, I need to add created_at scout's toSearchableArray. The problem with this is that when a user searches, results from created_at will also be queried.
If I understand you correctly you want to be able to filter based on the created_at column, but it shouldn't be searchable, ie entering "795" as a query shouldn't return all results where "795" is part of the timestamp?
I don't think Scout will allow you to achieve this in a simple way at the moment but it should still be possible.
Step 1 is to add the created_at column to the toSearchableArray() method. This will ensure the data is indexed by Meili.
Step 2 is to alter the configuration of the index where your model is searchable in order to exclude created_at from the list of searchable attributes. This is psuedo code and undocumented but it should look something like this:
$dummy = new Comment();
// Should resolve to an engine: https://github.com/laravel/scout/blob/f8aa3c3182fe97f56a6436fd0b28fcacfcbabc11/src/Searchable.php#L279
$engine = $dummy->searchableUsing();
// Should resolve to MeiliSearch\Endpoints\Indexes via a magic method that resolves the underlying Meili driver:
// https://github.com/laravel/scout/blob/33bbff0e3bfb1abd0ea34236c331fc17cdeac0bc/src/Engines/MeiliSearchEngine.php#L298
// ->
// https://github.com/meilisearch/meilisearch-php/blob/f25ee49b658f407af3d3f1f9a402997e7974b6bb/src/Delegates/HandlesIndex.php#L23
$index = $engine->index($dummy->searchableAs());
// https://github.com/meilisearch/meilisearch-php/blob/f25ee49b658f407af3d3f1f9a402997e7974b6bb/src/Endpoints/Delegates/HandlesSettings.php#L55
$index->updateSearchableAttributes(
['id','title', 'link', 'raw_text', 'subchan', 'nsfw']
);
Once created_at is indexed but not searchable you want to filter on the value. Meili has operators for numeric values.
Step 3 is to do a custom search using Scout:
Comment::search($query, function (Indexes $meilisearch, $query, $options) {
$options['filters'] = 'created_at>795484800';
return $meilisearch->search($query, $options);
});
Again, this is pseudo code – I haven't tested any part of it. I would really appreciate if Scout would implement support for customizing the index' settings on creation or exposing a method for updating the settings, allowing you to add driver specific settings in your configuration file for example.
i spent numerous hours debugging and getting the filter for dates to work.
this wont work as the where clause only accepts two arguments
Comment::search($query)->where('created_at', '>', 795484800)->get();
this also wont work because the arguments passed are not part of the two options that they have supported in the scout library
Comment::search($query, function (Indexes $meilisearch, $query, $options) {
$options['filters'] = 'created_at>795484800';
return $meilisearch->search($query, $options);
});
my solution for everyone out there trying to get this to work is to use the following:
$results = Event::search(
query: $request->get('query'),
callback: function (Indexes $meilisearch, $query, array $options) use ($request, $from, $to) {
$options['filter'] = "from <= 1667692800";
// dd($options);
return $meilisearch->rawSearch(
$query,
$options,
);
},
)->paginate();
hope this helps anyone else having issues as this wasted my morning searching for solutions until i decided to dig into the code in the library.
I solved my problem by using filterable attributes of Meilisearch. But it needs to be configured before running the search. I used php artisan tinker to solve this as follows, you might want to write an artisan command to do so.
$client = new MeiliSearch\Client('https://url_to_meilisearch_instance:7700');
$client->index('comments_index')->updateFilterableAttributes(['created_at']); // Replace your index_name
And that's about it. If you have a rather large dataset, you might want to run the following command to check the status:
$client->index('comments_index')->stats();
If the response contains isIndexing => false you're good to go. Now you may run the filter as usual,
Comment::search($query)->where('created_at', '>', 795484800)->get();

Fetching all database entries with their relationships using a Resource

So, I'm currently trying to fetch every entry from one database table and returning them using an APIResource. I wanna also return every relationship of those entries.
Here is my controller:
public function all()
{
return GameResource::collection(Game::all()->with('white_user', 'black_user', 'win_user')->get());
}
And the corresponding Resource:
public function toArray($request)
{
return [
'GmID' => $this->GmID,
'White_user' => new UserPublicResource($this->whenLoaded('white_user')),
'Black_user' => new UserPublicResource($this->whenLoaded('black_user')),
'Winner' => new UserPublicResource($this->whenLoaded('win_user')),
'Pgn' => $this->Pgn,
'StartTime' => $this->StartTime
];
}
I am aware that the Problem lies in the all() method which returns a collection which doesnt have a with() method.
Here is the error message:
Method Illuminate\Database\Eloquent\Collection::with does not exist.
I am wondering if there is an easy way to do what I want to and I can't seem to find anything in the docs or anyone on the internet who wanted something similar.
you are calling with after fetching data which is collection and collection don't have with method call this way will work it will fetch all data from game table.
return GameResource::collection(Game::with('white_user', 'black_user', 'win_user')->get());

Retrieving records from database using eloquent with optional query parameters

i have the following block of code in my Resource Controller:
$travel_company_id = Input::get('travel_company_id');
$transport_type = Input::get('transport_type');
$route_type = Input::get('route_type');
$travelRoutes = TravelRoute::where('travel_company_id', $travel_company_id)
->where('transport_type', $transport_type)
->where('route_type', $route_type)
->get();
Now what this does is it gets travelRoutes based on the parameters supplied. What i want is for it to do is perform a search based on the available parameters, that way if $route_type is empty the search will be performed only on travel_company_id and transport type.
Also if all the parameters are empty then it will simply do a get and return all available records.
I know i can do this with lots of if statements but then if i add a new parameter on the frontend i will have to add it to the backend as well, I was wondering if there was a much simpler and shorter way to do this in laravel.
The where method accepts an array of constraints:
$constraints = array_only(Input::all(), [
'travel_company_id',
'transport_type',
'route_type',
]);
$routes = TravelRoute::where($constraints)->get();
Warning: do not use Input::only() instead of array_only(). They're not the same.
Input::only() fills in any missing items with null, which is not what you want here.
This is pretty hacky and if you spend some time developing a solution I'm sure it could be much nicer. This assumes all the fields in the getSearchFields() function match the input names from the form and database.
/**
* Search fields to retrieve and search the database with. Assumed they match the
* column names in the database
*/
private function getSearchFields()
{
return ['travel_company_id', 'transport_type', 'route_type'];
}
public function search()
{
// Get a new query instance from the model
$query = TravelRoute::query();
// Loop through the fields checking if they've been input, if they have add
// them to the query.
foreach($this->getSearchFields() as $field)
{
if (Input::has($field))
{
$query->where($field, Input::get($field));
}
}
// Finally execute the query
$travelRoutes = $query->get();
}

Converting Laravel-4 Eloquent query results to arrays

I'm trying to get my route to insert a new row into the database, and if successful return the record (with its new primary key id) in some JSON. I'm getting the following error:
{
"error":
{
"type":"BadMethodCallException",
"message":"Call to undefined method Illuminate\\Database\\Query\\Builder::to_array()",
"file":"\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Query\\Builder.php",
"line":1418
}
}
This is my route:
Route::post('/client/create', function()
{
$client = Client::create(Input::all());
if($client)
{
return json_encode(array('Result' => 'OK', 'Record' => $client->to_array()));
}
else
{
return json_encode(array('Result' => 'ERROR', 'Message' => 'Error Inserting Record =('));
}
});
According to the Laravel docs I've read, you're supposed to use ->to_array() to convert your model to an array, and ::create returns an instance of the model if successfully inserted. I've checked the database, and the records are being inserted just fine.
By default if you were to return an Eloquent model directly it would convert the model to it's JSON representation. This is because the __toString magic method on each model returns the model as JSON by using the toJson method.
As such the model implements both the ArrayableInterface and JsonableInterface. That means you can directly call toJson or toArray on a model.
Now you can mark columns as hidden. This means that when a model is converted into it's array or JSON representation some columns are removed (think publicly accessible API, you don't want passwords showing up!). I'm not totally sure but maybe the ID of your model is being hidden.
At the end of the day, all you need to do is return the instance.
return $client;
It'll be converted to JSON for you automatically.
The to_array() method comes from Laravel 3. Use toArray() in Laravel 4.
I see question similar you try to return data to jquery jtable and same me
Player::orderBy($sort)->paginate($pagesize)->getCollection();
return Response::view(array('Result'=>'OK','Records'=>$player->toArray()));
for try many hour I found solution getcollection pull instance from object and then solve

Resources