I have 2 tables and I want to make 1 array of both tables data.
Logic
User has bids
Either user is bidder which results come from bids table based on user_id column
Or user is owner and received bids which comes from projects table based on user_id column
I want to merge this 2 arrays into 1 (regardless of user being bidder or receiving bids, I want get all bids at once)
Code
This is what I have currently, but it's not good solution in case user is both bidder and owner, with current code user will only receive data of his/her bids as bidder only.
$bids = Bid::where('user_id', '=', $user->id)->with(['project', 'project.user', 'user'])->get();
if(count($bids) > 0) {
return response()->json([
'data' => BidsResource::collection($bids),
'message' => 'Your data is ready.'
], 200);
} else {
$projects = Project::where('user_id', $user->id)->pluck('id');
$bids = Bid::whereIn('project_id', $projects)->with(['project', 'project.user', 'user'])->get();
return response()->json([
'data' => BidsResource::collection($bids),
'message' => 'Your data is ready.'
], 200);
}
I have already tried array_merge but it return errors (details below).
// as bidder
$bids1 = Bid::where('user_id', '=', $user->id)->with(['project', 'project.user', 'user'])->get();
// as project owner
$projects = Project::where('user_id', $user->id)->pluck('id');
$bids2 = Bid::whereIn('project_id', $projects)->with(['project', 'project.user', 'user'])->get();
// merge results
$bids = array_merge($bids1, $bids2);
return response()->json([
'data' => BidsResource::collection($bids),
'message' => 'Data is ready.'
], 200);
array_merge Errors
Code above return array_merge(): Expected parameter 1 to be an array, object given
If I add ->get()->toArray(); then it would return Trying to get property 'id' of non-object
Any suggestions?
Update
BidsResource file
public function toArray($request)
{
$arrayData = [
'id' => $this->id,
'amount' => $this->amount ? "$ " .number_format($this->amount, 0) : "$0",
'note' => $this->note,
'attachment' => $this->attachment ? url('images', $this->attachment) : null,
'accepted' => $this->accepted,
'results' => $this->results,
'user' => new UserResource($this->whenLoaded('user')),
'project' => new ProjectsResource($this->whenLoaded('project')),
'chats' => BidChatsResource::collection($this->whenLoaded('chats')),
'created_at' => $this->created_at ? $this->created_at->diffForHumans() : null,
'updated_at' => $this->updated_at ? $this->updated_at->diffForHumans() : null,
];
return $arrayData;
}
In your specific case, the proper and efficient way would be using an OR clause to get the records where either of the conditions is satisfied.
The code would be
$projects = Project::where('user_id', $user->id)->pluck('id');
$bids = Bid::where(function($query) use ($projects, $user){
$query->where('user_id', '=', $user->id)->orWhereIn('project_id', $projects);
})->with(['project', 'project.user', 'user'])->get();
As the results of $bids1 and $bids2 are objects of laravel collection, you can use merge() method of collections#method-merge
$bids = $bids1->merge($bids2);
Related
Controller code to view the API records
public function index()
{
$client=new Client();
$response = $client->request('GET', 'https://api.publicapis.org/entries');
$apidata = json_decode($response->getBody()->getContents(),true);
return view('apidata')->with('apidata', $apidata ['entries']);
}
to store the records into db
public function store()
{
set_time_limit(240);
$client=new Client();
$response = $client->request('GET', 'https://api.publicapis.org/entries');
$apidata = json_decode($response->getBody()->getContents(),true);
foreach($apidata ['entries'] as $entries) {
$entries = Apidata::updateorCreate([
'API'=> $entries['API'],
'Description'=>$entries['Description'],
'Auth'=>$entries['Auth'],
'HTTPS'=>$entries['HTTPS'],
'Cors'=>$entries['Cors'],
'Link'=>$entries['Link'],
'Category'=>$entries['Category']
]);
}
return redirect()->back()->with('message', 'Data Saved Successfully!');
}
}
Get records from external API
Save all the records into database
The records must not be duplicated in case we send multiple API calls
also how do i save the records in batch to avoid maximum time out for large entries
In your case you were using updateOrCreate method. So you can set a primary key field to determine if the same record occurs again, it will automatically just update the same record with the primary column.
Let us assume - "Auth" is a primary column, then you can save the records with updateOrCreate method as follows,
$entries = Apidata::updateorCreate(
[
'API' => $entries['API'],
],
[
'API' => $entries['API'],
'Description' => $entries['Description'],
'Auth' => $entries['Auth'],
'HTTPS' => $entries['HTTPS'],
'Cors' => $entries['Cors'],
'Link' => $entries['Link'],
'Category' => $entries['Category']
]
);
In such way you can avoid duplicate entries in laravel 9
How can I update multi rows by id using whereIn I'm tried this, but doesn't work
if (count($request->ids) > 0) {
$downloaded = PreCreatedUser::whereIn('id', $request->ids)->update(['downloaded' => 1]);
}
return response()->json([
'message' => true,
'data' => $downloaded
], 200);
Finally I found a way to solve this, according to Laravel documentation, if you want to update multi rows by a specific data in this case an array of ids you can use for integer type data "whereIntegerInRaw", and this was my solution, and finally works.
if (count($request->ids) > 0) {
$downloaded = PreCreatedUser::whereIntegerInRaw('id', $request->ids)->update(['downloaded' => "1"]);
}
return response()->json([
'message' => true,
'data' => $downloaded
], 200);
In Laravel, I am creating a message thread feature. My schema looks like this:
MessageThreads Table
column
id
MessageThreadParticapants Table
column
thread_id
user_id
And I have the corresponding models of MessageThread and MessageThreadParticapant. In the MessageThread model, I have the following relation:
public function users() {
return $this->hasMany(MessageThreadParticapant::class, 'thread_id', 'id');
}
Here is where things get funny. If I do:
MessageThread->users
I get an empty result. But if I do:
MessageThreadParticapant::where('thread_id', $same_thread_id)->get()
I get the correct amount of results back. What am I doing wrong here?
UPDATE
One of the suggestions was "hasMany(Model, 'foreign_key', 'local_key')" to be incorrect. Some more context,its failing my unit tests. I'm testing up a test as such:
public function testUsers() {
$thread1 = MessageThread::factory()->create();
$thread2 = MessageThread::factory()->create();
$this->assertCount(0, $thread1->users);
$this->assertCount(0, $thread2->users);
$user1 = User::factory()->create();
$user2 = User::factory()->create();
$user3 = User::factory()->create();
$user4 = User::factory()->create();
MessageThreadParticapant::factory()->create([
'user_id' => $user1->id,
'thread_id' => $thread1->id
]);
MessageThreadParticapant::factory()->create([
'user_id' => $user2->id,
'thread_id' => $thread1->id
]);
MessageThreadParticapant::factory()->create([
'user_id' => $user2->id,
'thread_id' => $thread2->id
]);
MessageThreadParticapant::factory()->create([
'user_id' => $user3->id,
'thread_id' => $thread2->id
]);
MessageThreadParticapant::factory()->create([
'user_id' => $user4->id,
'thread_id' => $thread2->id
]);
//PASSES!!!!
$this->assertCount(2, MessageThreadParticapant::where('thread_id', $thread1->id)->get());
//FAILS!!!
$this->assertCount(2, $thread1->users);
$this->assertCount(3, $thread2->users);
}
At bottom of my test:
//PASSES!!!!
$this->assertCount(2, MessageThreadParticapant::where('thread_id', $thread1->id)->get());
//FAILS!!!
$this->assertCount(2, $thread1->users);
In other tests, $thread->users works correctly in getting the right amount of users back. Why are these getting different results?
I solved this problem in two steps.
Refresh
Lazy loading apparently only represents that state of the object at the time that it was loaded. Meaning it's not retrieving new data from the DB when the joined property is called. To solve, just do a refresh on the model and then access the joined property.
$model->refresh();
$model->users;
String ID
I'm using UUID in Postegresql. Even those I am using $cast = ['id' => 'string']; in model, this is not enough. I also have to add:
protected $keyType = 'string';
I've got something like this
$query = Customer::find()
->select(['customer.name', 'surname', 'cityName' => 'cities.name', 'streetName' => 'streets.name'])
->joinWith(['city', 'street'])
->where(['group_id' => $id]);
When i do
return $query->all();
it returns only columns from customer table, but when i do something like this
$raw = $query->createCommand()->getRawSql();
return \Yii::$app->user_db->createCommand($raw)->queryAll();
it returns me all 4 columns. Why orm fails?
I'm using custom db connection (user), dynamicly connected after authorization. Anyway ActiveRecord->getDb() has been customized too and it works well till now.
it returns only columns from customer table, but when i do something like this.
Yes, that's right. Because Yii2 AR(Active Record) is ORM pattern. And it's try to return all result off query like object.
So, I will not tell the theory, I'd better suggest a solution variant:
$query = Customer::find()
->joinWith(['city', 'street'])
->where(['group_id' => $id])
->asArray()
->all();
return $query;
It's from Yii2 docs(performance tuning).
The result will be like:
[
all data selected from "customer",
['city' => all data selected from city joinWith],
['street' => all data selected from street joinWith]
]
I think, this is exactly what you need.
But, if you need objects. You can try marge objects to only one array.
$customer = Customer::find()
->joinWith(['city', 'street'])
->where(['group_id' => $id])
->all();
return [
'customer' => $customer,
'city' => $customer->city,
'street' => $customer->street,
];
you are using
->select(['customer.name', 'surname', 'cityName' => 'cities.name', 'streetName' => 'streets.name'])
so you will get selected columns only.
use,
$query = Customer::find()
->joinWith(['city', 'street'])
->where(['group_id' => $id])
->all();
this will give you all the columns
This API route is working fine and returning JSON response, currently it is returning category_id as a foreign key, I also want to get column 'name' from table 'category' in my JSON response, how to do it? Help shall be appreciated.
Route::get('/quizzes', function() {
$quizzes = App\Quiz::select('id','name','description','average_playtime','status','image','thumbnail','created_at','updated_at','category_id','user_id','category_name'
DB::raw('created_at >= DATE_SUB(CURDATE(),INTERVAL 10 day) as isNew')
)->where('status', 'active')->take(20)->get();
return Response::json(array(
'error' => false,
'quizzes' => $quizzes,
'status_code' => 200
));
});
Join to table category and get the category_name
Route::get('/quizzes', function() {
$quiz = new App\Quiz();
$selectClause = array(
$quiz.getTable().'id',
$quiz.getTable().'name',
$quiz.getTable().'description',
$quiz.getTable().'average_playtime',
$quiz.getTable().'status',
$quiz.getTable().'image',
$quiz.getTable().'thumbnail',
$quiz.getTable().'created_at',
$quiz.getTable().'updated_at',
$quiz.getTable().'category_id',
$quiz.getTable().'user_id',
'c.category_name',
DB::raw($quiz.getTable().'created_at >= DATE_SUB(CURDATE(),INTERVAL 10 day) as isNew')
);
$quizzes = App\Quiz::join('category AS c', 'c.category_id', '=', $quiz.getTable().'category_id')
->select($selectClause)
->where('status', 'active')
->take(20)
->get();
return Response::json(array(
'error' => false,
'quizzes' => $quizzes,
'status_code' => 200
));
});