Reputation: 47
I have draws on my site. Once a day, a new draw starts. But there is a problem that there is a duplicate of the draws. That is, I have a table named items
, in which there is a list of items from Dota 2, in this table there is a columnmarket_hash_name
, is_giveaway
. And there is a code that selects items to draw:
$betitem = \DB::table('items')->where('status', 0)->where('is_giveaway', 0)->where('steamid', 1)->where('price', '=', 26)->orderByRaw('RAND()')->take(1)->get();
After receiving this item, a drawing is created with the received parameters in the giveaway
table. An example of a response received to create a draw:
array(1) { [0]=> object(stdClass)#585 (14) { ["id"]=> int(553) ["assetid"]=> string(11) "18235855873" ["market_hash_name"]=> string(17) "Full-Bore Bonanza" ["classid"]=> string(206) "-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KW1Zwwo4NUX4oFJZEHLbXK9QlSPcUhpxJNSV6fVOqkx8rBbF51NQFov7eoJBV00v-HYjNL_Nmkq4OKh_LLOrbcmXlF6ck_j7nAoNqt0QHg_kFuMm36JdWWdQA7YwyG_QK3wLq8jZ7v6JjKzHFqsj5iuyi7wGzR_A" ["price"]=> float(26) ["steamid"]=> string(1) "1" ["type"]=> string(4) "card" ["bot"]=> string(1) "1" ["status"]=> int(0) ["created_at"]=> string(19) "2020-02-27 03:47:12" ["updated_at"]=> string(19) "2020-03-22 15:53:34" ["is_withdraw"]=> int(0) ["discount"]=> float(0) ["is_giveaway"]=> int(0) } }
The main problem is that a draw with this value of market_hash_name
is already on the site, and it still creates a new one with the same name. How can I skip duplicates?
Here is my function, which add draws:
public function add_giveaway()
{
$betitem = \DB::table('items')->where('status', 0)->where('is_giveaway', 0)->where('steamid', 1)->where('price', '=', 26)->orderByRaw('RAND()')->take(1)->get();
$raffling_price = $betitem[0]->price;
$green_tickets = $betitem[0]->price;
$market_name = $betitem[0]->market_hash_name;
$market_classid = $betitem[0]->classid;
$market_assetid = $betitem[0]->assetid;
$market_id = $betitem[0]->id;
$is_giveaway = Item::where('id', '=', $betitem[0]->id)->update(['is_giveaway' => '1']);
$check_duplicate = Item::where('market_hash_name')->where('is_giveaway', "=", 1)->get();
if ($raffling_price < 20) {
$max_users = mt_rand(5, 10);
} elseif ($raffling_price < 50) {
$max_users = mt_rand(10, 25);
} elseif ($raffling_price < 150) {
$max_users = mt_rand(25, 50);
} elseif ($raffling_price < 250) {
$max_users = mt_rand(50, 100);
}
$betitem_id = \DB::table('items')->where('status', 0)->where('price', '=', 26)->orderByRaw('RAND()')->take(1)->pluck('id');
\DB::table('giveaway_items')->where('id',$betitem_id)->update(['status' => 3]);
$giveaway = Giveaway::create(['max_user' => $max_users, 'green_tickets' => round($green_tickets / 15), 'price' => $raffling_price, 'items' => $market_name, 'classid' => $market_classid, 'assetid' => $market_assetid, 'item_id' => $market_id]);
}
$check_duplicate
it's test variable to get duplicates, but it doesn't work.
Where is problem? How to fix duplicates?
Upvotes: 1
Views: 403
Reputation: 18916
To be honest, this code is all over the place, in terms of style, snippets and using different facades. Main problem seems to lie within where('market_hash_name')
, this is not the correct way to do where logic.
I cleaned everything up, main point of logic is to retrieve a betItem until you find one that is not a duplicate, i would go for figuring out why your data is incorrect, but right now this fixes it. If a duplicate continue the while()
statement.
$betitem = null;
$found = false;
while(! $found) {
$betitem = $this->getBetItem();
$duplicate = $this->checkDuplicate($betitem);
if ($duplicate) {
continue ;
}
$betitem->is_giveaway = '1';
$betitem->save();
$found = true;
}
This code needs some helpers. Firstly how to fetch the betItem.
public function getBetItem()
{
return Item::where('status', 0)
->where('is_giveaway', 0)
->where('steamid', 1)
->where('price', 26)
->orderByRaw('RAND()')
->first();
}
Another helper is to check the duplicate.
public function checkDuplicate($betitem)
{
return Item::where('market_hash_name', $betitem->market_hash_name)
->where('is_giveaway', 1)
->exists();
}
For syntaxic sugar i added a maxUsers()
function.
public function maxUsers($betitem)
{
$raffling_price = $betitem->price;
if ($raffling_price < 20) {
return mt_rand(5, 10);
} elseif ($raffling_price < 50) {
return mt_rand(10, 25);
} elseif ($raffling_price < 150) {
return mt_rand(25, 50);
} elseif ($raffling_price < 250) {
return mt_rand(50, 100);
}
}
There is probably some way to go, you need to fiddle with your own code, i hope this example shows an example of some more clean code that should work. Also for these cases, it would be normal to do a transaction, which will secure the database can't write the same updates multiple times, but lock the table in the process. So the main function would look like this using all the helpers.
public function addGiveaway()
{
DB::transaction(function () {
$betitem = null;
$found = false;
while(! $found) {
$betitem = $this->getBetItem();
$duplicate = $this->checkDuplicate($betitem);
if ($duplicate) {
continue ;
}
$betitem->is_giveaway = '1';
$betitem->save();
$found = true;
}
$max_users = $this->maxUsers($betitem);
$giveaway = Item::where('status', 0)->where('price', '=', 26)->orderByRaw('RAND()')->first();
\DB::table('giveaway_items')->where('id', $giveaway->id)->update(['status' => 3]);
$giveaway = Giveaway::create([
'max_user' => $max_users,
'green_tickets' => round($betitem->price / 15),
'price' => $betitem->price,
'items' => $betitem->market_hash_name,
'classid' => $betitem->classid,
'assetid' => $betitem->assetid,
'item_id' => $betitem->id
]);
});
}
Upvotes: 1