Using Raw, how to return collection of updated row?
For example:
$updated = DB::table('users')->where('id', 1)->update(['votes' => 123]);
I was expecting dd($updated) to return updated row of collection but it returned 1.
{{$updated->votes}} should return 123
Try this
$updated = tap(DB::table('users')->where('id', 1))
->update(['votes' => 123])
->first();
That's not how it works. You can't expect this query will return you an object:
$updated = DB::table('users')->where('id', 1)->update(['votes' => 123]);
If you want to use Query Builder only as you mentioned in your question, you'll need to get an object manually:
$data = DB::table('users')->where('id', 1)->first();
With Eloquent you can use the updateOrCreate():
$data = User::where('id', 1)->updateOrCreate(['votes' => 123]);
This will return an object. update() will return boolean, so you can't use it here.
for version 6: another way with eloquent to return the new updated model by chaining the update method call through tap :
$user = tap($user)->update(['votes' => 123]);
This also returns the updated row:
$user = $user->fill(['votes' => 123])->save();
This trick worked for me:
$updated = DB::select("UPDATE users SET votes = 123 WHERE id = 1 RETURNING votes");
Then, since select returns an array: $votes = $updated[0]->votes;
And I believe you could even retrieve the entire row(s) using RETURNING *
This also work with prepared statements:
$updated = DB::select("UPDATE users SET votes = ? WHERE id = ? RETURNING votes", [$votes, $id]);
IMPORTANT NOTE
I am using a Postgres database. This will work only on a db that supports such a thing as RETURNING
you get the first row again after update see example bellow
$user = User::where('id', 1);
$userOld = $user->first(); // will return the first row
$isUserUpdated = $user->update(['name'=>'new name']); // will return true or false
$updatedUser = $user->first(); // now it will return you the latest updated data
by this example you have old data and new data and is data updated result, now we can return new data.
return response()->json(['status' => $isUserUpdated,'data'=>$updatedUser], 200);
In controller you write below code for update :
$updated = DB::table('users')->where('id', 1)->update(['votes' => 123])->get();
Related
Controller
public function detail(Peserta $peserta)
{
// get konfirmasi_id
$konfirmasi = KonfirmasiPembayaran::where('email',$peserta->email)->select('id')->get();
$payments = BankSettlement::whereIn('konfirmasi_id',array($konfirmasi->id))->get();
// dd($payments);
$tagihan = Tagihan::where([['peserta_id', $peserta->id],['type', 3]])->first();
return view('data.peserta.detail', ['data' => $peserta, 'payments' => $payments,'tagihan' => $tagihan]);
}
I want to display data from BankSettlement based on konfirmasi_id. Here I try to use WhereIn Query like this, but still error "Property [id] does not exist on this collection instance.".
$konfirmasi has data like the image above.
What is the correct way to display data from BankSettlement based on konfirmasi_id ? Thankyou
Try this changes:
$konfirmasi = KonfirmasiPembayaran::where('email',$peserta->email)->pluck('id')->toArray();
$payments = BankSettlement::whereIn('konfirmasi_id',$konfirmasi)->get();
This is the wrong way to change a collection to array.
$payments=BankSettlement::whereIn('konfirmasi_id',array($konfirmasi->id))->get();
You should do this
public function detail(Peserta $peserta)
{
// get konfirmasi_id
$konfirmasi = KonfirmasiPembayaran::where('email',$peserta->email)
->select('id')
->get()
->pluck('id')
->toArray(); //This will return an array of ids
$payments = BankSettlement::whereIn('konfirmasi_id',$konfirmasi)->get();
// dd($payments);
$tagihan = Tagihan::where([['peserta_id', $peserta->id],['type', 3]])->first();
return view('data.peserta.detail', ['data' => $peserta, 'payments' => $payments,'tagihan' => $tagihan]);
}
Edit:
Read Laravel Collections|Pluck
If you do not have to reuse the result of $konfirmasi then it would be better to use subquery. Writing a subquery is optimized way. if you write two different query then there will be two seperate database connection request.
Laravel subquery
$konfirmasi = KonfirmasiPembayaran::where('email',$peserta->email)->select('id');
$payments = BankSettlement::whereIn('konfirmasi_id', $konfirmasi )->get();
I want to change the status at $ result, to get the data at $ result I use query builder, but there is an error like that
$results = ClientVendor::where('client_id','=', $request->client_id)
->where('vendor_id','=',$request->vendor_id)
->get();
$results->status = $request->status;
$results->save();
return response()->json($results);
You cant do this because you call whole collection where is many elements. Call just single record, then you can update it.
When you use get() you call collection
When you use first() or find($id) then you get single record that you can update.
Look at example:
$results = ClientVendor::where('client_id', $request->client_id)
->where('vendor_id',$request->vendor_id)
->first(); // this point is the most important to change
$results->status = $request->status;
$results->save();
return response()->json($results);;
Good luck!
You can try this one too.
$results = ClientVendor::where('client_id','=', $request->client_id)
->where('vendor_id','=',$request->vendor_id)
->update([
'status' => $request->status
]);
Try this:
$results = ClientVendor::where('client_id', $request->client_id)
->where('vendor_id',$request->vendor_id)
->first();
$results->status = $request->status;
$results->save();
return response()->json($results);
It depends on your needs, if you want to :
Get and update one record, you should use first() or firstOrFail() instead of get(). Should be look like this :
$results = ClientVendor::where('client_id', $request->client_id)
->where('vendor_id',$request->vendor_id)
->first();
$results->status = $request->status;
$results->save();
return response()->json($results);
Get and update multiple records, yes you can use get(), but you should do foreach and then update the single record one by one. just like this :
$results = ClientVendor::where('client_id', $request->client_id)
->where('vendor_id',$request->vendor_id)
->get();
foreach($results as $result){
$result->status = $request->status;
$result->save();
}
return response()->json($results);
Many have suggested using first() instead of get(). I think fistOrFail() would be a better option to handle null results.
Otherwise, in cases where the result is null, you'd get Call to a member function save() on null error.
Eg:
ClientVendor does not have a record with either client_id or vendor_id matching $request->client_id or $request->client_id respectively.
$result = ClientVendor::where('client_id', $request->client_id)
->where('vendor_id',$request->vendor_id)
->first();
$result->status = $request->status; //produces error Creating default object from empty value
$result->save(); //produces error "Call to a member function save() on null" because $result will be empty
The above code produces 2 exceptions: 1. "Creating default object from empty value" on lines $result->sataus = .. and 2."Call to a member function save() on null" on line $result->save because $result will be empty.
To fix that, you would call firstOrFail() like so.
$result = ClientVendor::where('client_id', $request->client_id)
->where('vendor_id',$request->vendor_id)
->firstOrFail();
$result->status = $request->status;
$result->save();
This fix, firstOrFail, when there are no results would produce a 404, a handled error, and the subsequent lines would not be executed.
For situations where you query using find($id), it is better to use findOrFail($id)
If you need to update one item use find with it's primary key & then update.Or without primary key then use where & first.then update as like this Just Use
$results = ClientVendor::where('client_id', $request->client_id)
->where('vendor_id',$request->vendor_id)
->first();
$results->update([
'status'=>$request->status
]);
return response()->json($results);
I wants to know how to check if the return of Eloquent Query is single row from DB or multiple rows.
I tried $record->count() but it always return a value greater than 1 in the 2 cases.
For example:
$record = User::first();
return $record->count(); //it return the count of columns in users table
and if I tried to get all users;
$record = User::all();
return $record->count(); //it return the count of all rows in users table
So how to deal with this case ?
You can use the instanceof construction to check what kind of data your variable is.
For your examples, this will likely be something like this:
$record = User::first();
$record instanceof \App\User; // returns true
$record instanceof \Illuminate\Database\Eloquent\Collection; // returns false
$record = User::all();
$record instanceof \App\User; // returns false
$record instanceof \Illuminate\Database\Eloquent\Collection; // returns true
Docs: https://secure.php.net/instanceof
$record = ......;
if($record instanceof \Illuminate\Support\Collection){
// its a collection
}
elseif($record instanceof \App\User){
// its a single url instance
}
However, above will not work directly if you are using DB builders :
$record = DB::table('users')->get();
$record is an array. So you need to hydrate it so you can use above logic on it :
if(is_array($record){
$record = \App\User::hydrate($record);
}
Now you can use if else logic on $record as its converted from an array to \Illuminate\Database\Eloquent\Collection which internally extends from \Illuminate\Support\Collection
Also, second case if someone did first() instead of get():
$record = \DB::table('users')->first();
Then $record is an stdClass object. so you can avoid hydration and consider it as a single user data.
I am concerned about the system logic and patterns where you need to have this kind of conditional. If possible, I would recommend to refactor in such a way that you function always knows if it's a collection or an instance. You can use type hints in functions to be more clear.
first() always returns only 1 row
$record = User::first(); // this will return only 1 records
To get number of rows in users table you need to create another query
$allrow = User::all();
return $allrow->count();
OR
$allrow = DB::table('users')->get();
return $allrow->count();
User::all() returns an array of User So the simple way is to check if is an array.
if (is_array($record)){
}
Am trying to reuse a query but it fails.
In my method I have:
public function getPacked($from, $to){
$initquery = RealTimeTblTrucks::find()
->leftJoin('tbl_truck_history','tbl_truck_history.truck_id=tbl_trucks.id')
->where(["between","tbl_truck_history.created_at",$from,$to])
->andWhere(["tbl_truck_history.status"=>20]);
$data = [];
$data[SELF] =$initquery
->andWhere(["tbl_trucks.truck_category"=>28])
->count();
$data[NORMAL] = $initquery->andWhere(["tbl_trucks.truck_category"=>27])
->count();
$data[BULKER] = $initquery->andWhere(['in', 'tbl_trucks.truck_category', [26,34]])
->count();
return $data;
}
Now the first ($data[SELF]) returns the correct information but the next ones NORMAL and BULKER didn't return the correct information.
When I check on the raw query I can see that the last two are affected by the first one such that the new query at $data[NORMAL] contains a check for truck_category = 20 which should only be executed on the first array item (SELF).
How to refactor this to make it work?
Advantage of clone over creation a new object, is that, all properties will be copied into the new object instead of resetting them. This is quite useful when you use query builder.
public function getPacked($from, $to) {
$initquery = RealTimeTblTrucks::find()
->leftJoin('tbl_truck_history','tbl_truck_history.truck_id=tbl_trucks.id')
->where(["between","tbl_truck_history.created_at",$from,$to])
->andWhere(["tbl_truck_history.status"=>20]);
$data = [];
$querySelf = clone $initquery;
$data[SELF] = $querySelf
->andWhere(["tbl_trucks.truck_category"=>28])
->count();
$queryNormal = clone $initquery;
$data[NORMAL] = $queryNormal->andWhere(["tbl_trucks.truck_category"=>27])
->count();
$queryBulker = clone $initquery;
$data[BULKER] = $queryBulker->andWhere(['in', 'tbl_trucks.truck_category', [26,34]])
->count();
return $data;
}
Refer Yii2 clone detail
How can I rewrite this code in order to get last inserted record from the table?
$repository = $entityManager->getRepository('AdminBundle:MyTable');
$product = $repository->find($id);
I tried something like
$repository->findBy(array('id','DESC')->setMaxResults(1);
But it did not work for me.
You could get the latest record by using findBy() with order by, limit and offset parameters
$results = $repository->findBy(array(),array('id'=>'DESC'),1,0);
First argument is for filter criteria
Second argument takes order by criteria
Third argument is for limit
Fourth argument sets offset
Note it will return you the results set as array of objects so you can get single object from result as $results[0]
FindBy() Examples
Instead of hacking code where you want to use it, you can also create a repository method and call it when necessary.
/**
* Repository method for finding the newest inserted
* entry inside the database. Will return the latest
* entry when one is existent, otherwise will return
* null.
*
* #return MyTable|null
*/
public function findLastInserted()
{
return $this
->createQueryBuilder("e")
->orderBy("id", "DESC")
->setMaxResults(1)
->getQuery()
->getOneOrNullResult();
}
References:
https://symfony.com/doc/current/doctrine.html#querying-for-objects-the-repository
After looking for one I decided to try it myself, I think it was much less verbose:
$myRepository->findOneBy([], ['id' => 'DESC']);
Please try the below one
$repository = $entityManager->getRepository('AdminBundle:MyTable');
$repository->setMaxResults(1)->orderBy('id', 'DESC');
$results = $repository->getQuery()->getSingleResult();
Reference:
https://undebugable.wordpress.com/2016/01/27/symfony2-querybuilder-find-first-and-find-last-record-in-table/
You can add these functions to your repository:
public function getLastRow(): ?YourEntity
{
return $this->findOneBy([], ['id' => 'DESC']);
}
public function getLastId(): int
{
$lastRow = $this->getLastRow();
return $lastRow ? $lastRow->getId() : 0;
}
You can be collected by getting the id of the inserted object
$em->persist($entity);
$em->flush();
$entity->getId();
OR
$entitymanager->getRepository("entity")->findBy([],["id"=>desc])->getId();