I do parsing matches for DotA 2. Through a third-party API, I get current, future and past matches. But the problem how i understand, it's updateOrCreate function does not work. When parsing starts, it saves the values, but does not update the current ones. Here is an example of the answer that I get https://pastebin.com/KCcG6rJc, in this answer there is what teams are playing now, there are match_id of teams, if the teams are competing with each other, this value is the same. Using the example of this parsing result, I received the following record in the Database:
The maches table, the match_id value got there - 560004, that's right. But in the teams table, where these commands are indicated, match_id is null.
At my parser i has this code:
foreach ($live_matches as $live) {
if ($live->tournament_id != $tournament->id) {
continue;
}
$filtered_matches[] = $live;
foreach ($teams as &$team) {
if (false !== strpos($live->slug, $team->slug)) {
$team->match_id = $live->id;
$logo = $team->image_url;
var_dump($team);
exit;
}
}
}
var_dump($team); exit; say me:
object(stdClass)#1222 (8) {
["acronym"]=>
string(8) "ThunderP"
["id"]=>
int(2671)
["image_url"]=>
string(93) "https://cdn.pandascore.co/images/team/image/2671/87033C79D6D1A70A66941BC8649EA5988D74582C.png"
["location"]=>
string(2) "PE"
["modified_at"]=>
string(20) "2020-04-30T01:51:51Z"
["name"]=>
string(16) "Thunder Predator"
["slug"]=>
string(16) "thunder-predator"
["match_id"]=>
int(560004)
}
i.e. I get match_id, but at database it's not add.
And here is my full function, which update or create:
public function saveUpdate(int $tournament_id, array $tournament_teams, string $full_name, array $matches)
{
$tournament = Tournament::updateOrCreate([
'tournament_id' => $tournament_id,
'league_name' => $full_name
]);
foreach ($matches as $match) {
if ($match->status == 'not_started') {
$status = 0;
}
if ($match->status == 'running') {
$status = 1;
}
if ($match->status == 'finished') {
$status = 2;
}
$team = Tournament_teams::where('team_id', $match->winner_id)->first();
Tournament_matches::updateOrCreate([
'name' => $match->name,
'started_at' => Carbon::parse("$match->begin_at,")->setTimezone('Europe/Berlin'),
'ended_at' => $match->end_at,
'winner_id' => $team->id ?? null,
'status' => $status,
'match_id' => $match->id,
'live' => $match->live_url,
]);
}
foreach ($tournament_teams as $team) {
Tournament_teams::updateOrCreate([
'tournaments_id' => $tournament->id,
'team' => $team->name,
'slug' => $team->slug,
'logo' => $team->image_url,
'team_id' => $team->id,
], [
'match_id' => $team->match_id ?? null,
]);
}
}
For example, if I delete 1 column value from the teams table and start parsing, then the value in this column will not be created. That is, it creates data, but does not update.
And now teams with match_id 560334 are playing and the tournament_teams table doesn’t have such match_id, I searched for playing teams by name and found that there are 1 of the playing teams in the database 3 times in a row. That is, one record has match_id = null, the others of the same match_id commands have old ones. For some reason, the data on the current is not updated and empty values are received in the database, although 50% of the values are. Here is screenshot with highlighted commands for which for example data is not updated:
Where could my mistake be? Why does var_dump pass me match_id, but this value does not get into the database? Where could my mistake be? I use Laravel 5.1. If you need to clarify any details - ask, thank you for your help.
You are using wrongly the updateOrCreate() method.
As the documentation says:
You may also come across situations where you want to update an existing model or create a new model if none exists.
// If there's a flight from Oakland to San Diego, set the price to $99.
// If no matching model exists, create one.
$flight = App\Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99, 'discounted' => 1]
);
If I understood well your problem, you are doing it in the opposite way:
Tournament_teams::updateOrCreate([
'match_id' => $team->match_id ?? null,
], [
'tournaments_id' => $tournament->id,
'team' => $team->name,
'slug' => $team->slug,
'logo' => $team->image_url,
'team_id' => $team->id,
]);
Also, for this you don't need to use updateOrCreate() but firstOrCreate() for example:
$tournament = Tournament::firstOrCreate([
'tournament_id' => $tournament_id,
'league_name' => $full_name
]);
PS: If it is possible, I recommend you to use a newer Laravel version.
Related
I got a schedules table and i want it to have any duplicates. If the user puts same datas in the form that has already in the database it will not go to dd('exists') does anyone know what seems to be the problem?
Here is my update
$schedule = Schedule::findOrFail($id);
$validate = Schedule::where('subject_code_id',$request->subject)
->where('teacher_id',$request->teacher)
->where('room_id',$request->room)
->where('start_time',$request->start_time)
->where('end_time',$request->end_time)
->where('school_year',$request->schoolyr)
->where('day',$request->days)
->where('term',$request->term)
->where('semester',$request->sem)
->count();
if($validate == 1){
dd('exist');
} else{
$schedule->update($request->all());
}
tried
dd($request->all());
I got
array:11 [
"id" => 9
"term" => "2"
"semester" => "2"
"start_time" => "10:30 PM"
"end_time" => "12:30 AM"
"scid" => 10
"teacher_id" => 5
"room_id" => 6
"subject_code_id" => 9
"day" => "SAT"
"school_year" => "2020"
]
Instead of using the count method to determine if any records exist that match your query's constraints, you may use the exists and doesntExist methods:
$schedule = Schedule::findOrFail($id);
$validate = Schedule::where('subject_code_id',$request->subject)
->where('teacher_id',$request->teacher)
->where('room_id',$request->room)
->where('start_time',$request->start_time)
->where('end_time',$request->end_time)
->where('school_year',$request->schoolyr)
->where('day',$request->days)
->where('term',$request->term)
->where('semester',$request->sem)
->exists();
if($validate){
dd('exist');
} else{
$schedule->update($request->all());
}
Please visit to see details - aggregates
you can easily do that with laravel unique validation by using Rule class as below
$this->validate($request, [
'subject_code_id' => [
Rule::unique('schedules')->where(function ($query) use($request) {
return $query->where('teacher_id', $request->teacher); //you can add all conditions here
}),
],
]);
for more see unique validation rules here
use first() method instead of count()
$schedule = Schedule::findOrFail($id);
$validate = Schedule::where('subject_code_id',$request->subject)
->where('teacher_id',$request->teacher)
->where('room_id',$request->room)
->where('start_time',$request->start_time)
->where('end_time',$request->end_time)
->where('school_year',$request->schoolyr)
->where('day',$request->days)
->where('term',$request->term)
->where('semester',$request->sem)
->first();
if($validate){
dd('exist');
} else{
$schedule->update($request->all());
}
All I want here is to be able to save all the ID's of services into the pivot table associated with the given keywords/tags but at the moment all it does is that it takes the last ID of the created object and saves into the pivot table with different keywords. let's say for example I enter [id1 => service1, id2 => service2] and [id1 = > keyword1, id2 => keyword2, id3 => keyword3] instead of it saving only id2 of service2 and all the keywords I want it to save all the Ids of all of the services and the keywords. I hope it makes sense
foreach($params['service'] as $key => $value){
$service = Service::firstOrNew(['service' => $value, 'price' => $params['price'][$key], 'business_id' => $params['business_id']]);
$service->service = $value;
$service->price = $params['price'][$key];
$service->business_id = $params['business_id'];
$service->save();
}
foreach($params['keywords'] as $keyword){
$cleaned_keyword = self::cleanKeywords($keyword);
$newKeyword = Keyword::firstOrNew(['keyword' => $cleaned_keyword]);
$newKeyword->keyword = $cleaned_keyword;
$newKeyword->save();
$service->keywords()->syncWithoutDetaching([$newKeyword->id => ['business_id' => $params['business_id']]]);
}
This is something I would expect but it is tricky because a single or 2 services for example can have multiple keywords. NOTE: I had manually changed these values in the database
These are the results from a dd($params)
Based on the dd($params).attached is the result,only
"service" => array:2[
1 => "Mobile development"
]
was saved in the pivot table and got assigned all the keywords
Please correct me if this is a good approach, I managed to solve this by having an inner loop.
foreach($params['service'] as $key => $value) {
$service = Service::firstOrNew(['service' => $value, 'price' => $params['price'][$key], 'business_id' => $params['business_id']]);
$service->service = $value;
$service->price = $params['price'][$key];
$service->business_id = $params['business_id'];
$service->save();
foreach($params['keywords'] as $keyword) {
$cleaned_keyword = self::cleanKeywords($keyword);
$newKeyword = Keyword::firstOrNew(['keyword' => $cleaned_keyword]);
$newKeyword->keyword = $cleaned_keyword;
$newKeyword->save();
$service->keywords()->syncWithoutDetaching([$newKeyword->id => ['business_id' => $params['business_id']]]);
}
}
I have 3 models:
Match Team Player
And i want to create a table with the following structure:
id | match_id | team_id | player_id
So that i can associate the 3 models i refered.
I created a 4th model MatchPlayers for the table i referred and I can use the 'search' functions without a problem. Like this:
$match->matchPlayers()->first()->team()->get()
And it returns the excpected result, but I cant do a
$match->matchPlayers()->sync([])
So, how should i solve this? Is my relationship wrong or the sync method isnt allowed on a 3 model relationship and I shoud use other method?
Thanks in advance
Edit:
Match.php
public function teamPlayers(){
return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}
Team.php
public function matchTeamPlayers(){
return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}
Player.php
public function matchTeamPlayers(){
return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}
MatchPlayer.php
public function player(){
return $this->belongsTo('\Modules\Players\Entities\Player');
}
public function match(){
return $this->belongsTo('\Modules\Matchs\Entities\Match');
}
public function team(){
return $this->belongsTo('\Modules\Teams\Entities\Team');
}
If you've followed the Laravel documentation on Pivot tables and Many-Many relationships found here, and it's still not working, you might have more luck with "Attach". For example;
$matchPlayer = MatchPlayer::create([...]);
$match->matchPlayers()->attach($matchPlayer)
A good example of sync vs attach can be found here
Using a fourth model for this kind of relationship makes sense, as it gives you a navigation property for the third relation on your pivot table. This way you can form more complex queries this way.
For your particular problem, syncing based on match_id and team_id, I would simply do something like this:
$matchId = 123;
$teamId = 234;
$rows = [
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 345],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 346],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 347],
];
// remove all previously stored connections
MatchPlayer::where('match_id', $matchId)
->where('team_id', $teamId)
->delete();
// insert the news ones
// (you could also use MatchPlayer::create() per item or
// $matchPlayer->save(), it doesn't matter)
MatchPlayer::insert($rows);
If this operation occurs very frequently, you will potentially burn through a lot of id values of the pivot table. In this case you could also perform a more efficient sync, which is slightly more complex:
$matchId = 123;
$teamId = 234;
$rows = [
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 345],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 346],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 347],
];
// delete all players that are not among the new data anymore
MatchPlayer::where('match_id', $matchId)
->where('team_id', $teamId)
->whereNotIn('player_id', array_pluck($rows, 'player_id'))
->delete();
// remove rows from new data that already exist
$exist = MatchPlayer::where('match_id', $matchId)
->where('team_id', $teamId)
->pluck('player_id')
->toArray();
$rows = array_filter($rows, function ($value, $key) use ($exist) {
return ! in_array($value['player_id'], $exist);
});
// then we store the remaining data
MatchPlayer::insert($rows);
I want to display all documents (select *) with sub-documents in PHP.
I know how to query all find() but I have no idea how to do it when I have sub-documents. I don't know if there's something like find() or I need to make loops fo every sub-documents that I'd have.
This would be the code
$mongodatabase->insertOne(
['name' => 'Alex',
'surname' => 'Turner',
'country' => 'England',
'birth' => array(
'day' => 6,
'month' => 'january',
'year' => 1986
),
]);
Something easy, just to learn. When I try a var_dump of day I get Undefined index and NULL.
$client = new MongoDB\client;
$db = $client->database;
$mongodatabase = $db->document;
$document = $mongodatabase->find();
foreach ($document as $doc) {
var_dump($doc->day);
}
However, I'd like to query all.
Use $exists - It helps us in identifying the elements which are not empty
db.collection_name.find({
"birth.day" : {
$exists : true
}
});
If you need to check not null and empty, then we need to use $type together with $exists, $type can be passed with different values and 10 is for null check
db.collection_name.find({
"birth.day" : {
$not : { $type : 10 },
$exists : true
}
});
when u find the exactly data from mongoldb u can use the shelter to limit the field
eg:
db.xxxxx.find(
{'status':'DELIVRD'}
);
I have the following method in my user class:
/**
* Get all organisations for user (if owner)
*
* #param
*/
public function getOrganisationsOwned()
{
// If the user is owner of any one or many organisations then return this list
return Organisation::leftJoin('subscription_plans', 'organisations.subscription_plan_id', '=', 'subscription_plans.id')
->where('organisations.owner_id', '=', $this->id)
->select('organisations.*', 'subscription_plans.*')
->get();
}
The method essentially queries and joins two tables. Each table has a column called title.
The output from the above generates the rows as desired with the right info, but returns only one title column, from the right table (subscription_plans) but not the column title from the left table (organisations). I also notice it is dropping the timestamps from one table also, as these are of the same column name.
I understood that
->select('organisations.*', 'subscription_plans.*')
would make the query return both columns. What am I missing? Happy new year!
PS: below is a copy of the dd() contents for the collection, with title only appearing once.
#attributes: array:44 [▼
"id" => 1
"title" => "Monthly Subscription"
"address_1" => "34 Florence Street"
"address_2" => ""
"suburb" => "Hornsby"
"state" => "NSW"
"postcode" => "2077"
"country_id" => 12
"currency_id" => 12
"time_zone_id" => 109
"phone" => "0392144497"
"website" => "http://www.Tremblay.com/est-aspernatur-et-ut-provident.html"
"business_id" => "82297955560"
"tax_registration" => 1
"logo" => "8aa656de-2bc2-4e14-dddd-e02fbcd2b76f"
"quote_terms_days" => 14
"invoice_terms_days" => 14
"fiscal_start_id" => 7
"industry_id" => 4
"company_size_id" => 3
"date_format_id" => 2
"date_time_format_id" => 20
"owner_id" => 1
"gateway_id" => "1"
"gateway_username" => "xxx"
"gateway_password" => "xxx"
"gateway_signature" => "xxx"
"gateway_accepted_cards" => "[1, 2, 3]"
"subscription_plan_id" => 1
"trial_ends_at" => "2015-11-07"
"grace_ends_at" => "2016-02-10"
"subscription_ends_at" => "2016-01-11"
"latitude" => "-33.70433500"
"longitude" => "151.10161900"
"registration" => "done"
"deleted_at" => null
"created_at" => "2016-01-01 14:59:47"
"updated_at" => "2016-01-01 14:59:47"
"amount" => "9.09"
"gst" => "0.91"
"gst_amount" => "10.00"
"billing_cycle" => "MONTH"
"trial_period_days" => 30
"grace_period_days" => 30
]
The "missing" title column contains:
'title' => 'ABC Electrical'
There is some misunderstanding as to what I suggested: instead of using *, you could list the field names one by one and provide aliases for the 2 title fields. This does not mean that you should keep the 'organisations.*', 'subscription_plans.*' and add the 2 title fields to the select list with aliases because this way you select both title fields twice, wasting memory and processor time.
You should not include the * forms in the select list, but list each field individually, with the 2 title fields marked with aliases:
public function getOrganisationsOwned()
{
// If the user is owner of any one or many organisations then return this list
return Organisation::leftJoin('subscription_plans', 'organisations.subscription_plan_id', '=', 'subscription_plans.id')
->where('organisations.owner_id', '=', $this->id)
->select('organisations.id', 'organisations.title AS org_title', ..., 'subscription_plans.subscription_plan_id', 'subscription_plans.title AS plan_title', ...)
->get();
}
Yeah, I know, listing so many field one by one is a pain in the ***, however, each field is retrieved once and only once, at it is clear that you are fetching what is needed.
#Shadow's suggestion worked, although you should note, this method allows you to select all the fields, but only "rename" columns or rather alias them so you can still access the proper value when using joins. The old value will still be overridden, but now you can use your alias with the correct value.
The below is now working:
public function getOrganisationsOwned()
{
// If the user is owner of any one or many organisations then return this list
return Organisation::leftJoin('subscription_plans', 'organisations.subscription_plan_id', '=', 'subscription_plans.id')
->where('organisations.owner_id', '=', $this->id)
->select('organisations.*', 'organisations.title AS org_title', 'subscription_plans.*', 'subscription_plans.title AS plan_title')
->get();
}