Laravel - แถวสุ่มฝีปากหรือคล่องแคล่ว


242

ฉันจะเลือกแถวสุ่มโดยใช้ Eloquent หรือ Fluent ในกรอบงาน Laravel ได้อย่างไร

ฉันรู้ว่าโดยใช้ SQL คุณสามารถสั่งซื้อโดย RAND () อย่างไรก็ตามฉันต้องการรับแถวสุ่มโดยไม่นับจำนวนระเบียนก่อนที่จะเริ่มต้นแบบสอบถาม

ความคิดใด ๆ


ไม่มีวิธีที่ดีที่สุดในการทำเช่นนี้โดยไม่ต้องดำเนินการอย่างน้อยสองแบบสอบถาม
NARKOZ

คำตอบ:


587

Laravel> = 5.2:

User::all()->random();
User::all()->random(10); // The amount of items you wish to receive

หรือ

User::inRandomOrder()->get();

หรือเพื่อรับจำนวนเรคคอร์ดเฉพาะ

//5 indicates the number of records
User::inRandomOrder()->limit(5)->get();

Laravel 4.2.7 - 5.1:

User::orderByRaw("RAND()")->get();

Laravel 4.0 - 4.2.6:

User::orderBy(DB::raw('RAND()'))->get();

Laravel 3:

User::order_by(DB::raw('RAND()'))->get();

ตรวจสอบบทความนี้ในแถวสุ่มของ MySQL Laravel 5.2 สนับสนุนนี้สำหรับรุ่นเก่าไม่มีการแก้ปัญหาที่ดีกว่าแล้วใช้RAW แบบสอบถาม

แก้ไข 1:ตามที่ระบุไว้โดยดับเบิล Gras, orderBy () ไม่ยอมให้อะไรอื่นแล้วหรือ ASC DESC ตั้งแต่นี้การเปลี่ยนแปลง ฉันปรับปรุงคำตอบของฉันตาม

แก้ไข 2: Laravel 5.2 ในที่สุดก็ใช้ฟังก์ชั่น wrapperสำหรับสิ่งนี้ มันเรียกว่าinRandomOrder ()


81
แทนที่ 'get' ด้วย 'first' หากคุณต้องการแถวเดียว
Collin ราคา

14
สำหรับการใช้ PostgreSQL'RANDOM()'
dwenaus

2
คำเตือน: สำหรับชุดข้อมูลขนาดใหญ่จะช้ามากเพิ่มประมาณ 900 มิลลิวินาทีสำหรับฉัน
S ..

3
เราสามารถแบ่งหน้านี้ได้หรือไม่?
Irfandi D. Vendy

3
คุณสามารถอย่างไรก็ตามการเรียงลำดับจะสุ่มในทุกหน้าใหม่ ซึ่งไม่มีเหตุผลเพราะมันเหมือนกับ F5 ที่คุณกด
aebersold

49

มันใช้งานได้ดี

$model=Model::all()->random(1)->first();

นอกจากนี้คุณยังสามารถเปลี่ยนอาร์กิวเมนต์ในฟังก์ชันสุ่มเพื่อรับมากกว่าหนึ่งระเบียน

หมายเหตุ: ไม่แนะนำหากคุณมีข้อมูลจำนวนมากเนื่องจากจะเป็นการดึงข้อมูลแถวทั้งหมดก่อนแล้วจึงส่งกลับค่าสุ่ม


61
ข้อเสียที่ชาญฉลาดคือการดึงข้อมูลทั้งหมด
Gras Double

3
ที่นี่สุ่มเรียกว่าวัตถุการเก็บรวบรวมไม่แบบสอบถาม sql ฟังก์ชั่นแบบสุ่มจะดำเนินการในด้าน PHP
astroanu

@astroanu ถูกต้อง แต่เมื่อต้องการเติมคอลเล็กชันนั้นแถวทั้งหมดจะถูกสอบถาม
MetalFrog

1
ฉันอาจจะผิด แต่ดูเหมือนจะไม่ทำงานเมื่อพารามิเตอร์ที่ส่งผ่านไปยังฟังก์ชั่นแบบสุ่มเหมือนกับขนาดของคอลเลกชัน
Brynn Bateman

มันไม่ดี ... วิธีนี้คุณจะเรียกข้อมูลทั้งหมดและรับแบบสุ่ม หากตารางของคุณมีบันทึกมากเกินไปอาจเป็นผลเสียต่อแอพของคุณ
Anderson Silva

34

tl; dr:ปัจจุบันมีการใช้งานใน Laravel แล้วโปรดดู "แก้ไข 3" ด้านล่าง


น่าเศร้า ณ วันนี้มีข้อแม้บางอย่างที่มี->orderBy(DB::raw('RAND()'))วิธีแก้ปัญหาที่เสนอ:

  • มันไม่ใช่ DB ผู้ไม่เชื่อเรื่องพระเจ้า เช่นการใช้ SQLite และ PostgreSQLRANDOM()
  • ยิ่งกว่านั้นโซลูชันนี้ใช้ไม่ได้อีกต่อไปนับตั้งแต่การเปลี่ยนแปลงนี้ :

    $direction = strtolower($direction) == 'asc' ? 'asc' : 'desc';


แก้ไข:ตอนนี้คุณสามารถใช้เมธอด orderByRaw () :->orderByRaw('RAND()')วิธีการ:อย่างไรก็ตามเรื่องนี้ยังคงไม่เชื่อเรื่อง DB

FWIW, CodeIgniter ดำเนินการพิเศษ RANDOMทิศทางการเรียงลำดับซึ่งจะถูกแทนที่ด้วยไวยากรณ์ที่ถูกต้องเมื่อสร้างแบบสอบถาม นอกจากนี้ยังดูเหมือนว่าจะใช้งานค่อนข้างง่าย ดูเหมือนว่าเรามีผู้สมัครเพื่อปรับปรุง Laravel :)

อัปเดต: นี่คือปัญหาเกี่ยวกับเรื่องนี้บน GitHub และอยู่ระหว่างการพิจารณาของฉันคำขอดึง


แก้ไข 2: Let's ตัดการไล่ล่า ตั้งแต่ Laravel 5.1.18 คุณสามารถเพิ่มมาโครในตัวสร้างคิวรีได้:

use Illuminate\Database\Query\Builder;

Builder::macro('orderByRandom', function () {

    $randomFunctions = [
        'mysql'  => 'RAND()',
        'pgsql'  => 'RANDOM()',
        'sqlite' => 'RANDOM()',
        'sqlsrv' => 'NEWID()',
    ];

    $driver = $this->getConnection()->getDriverName();

    return $this->orderByRaw($randomFunctions[$driver]);
});

การใช้งาน:

User::where('active', 1)->orderByRandom()->limit(10)->get();

DB::table('users')->where('active', 1)->orderByRandom()->limit(10)->get();


แก้ไข 3:ในที่สุด! ตั้งแต่ Laravel 5.2.33 ( changelog , PR # 13642 ) คุณสามารถใช้วิธีเนทีฟinRandomOrder():

User::where('active', 1)->inRandomOrder()->limit(10)->get();

DB::table('users')->where('active', 1)->inRandomOrder()->limit(10)->get();

คุณควรเปลี่ยนชื่อมาโคร 5.1 เป็น inRandomOrder เพื่อให้สามารถใช้งานร่วมกันได้) รายละเอียดรายละเอียด :)
Sander Visser

นั่นเป็นสิ่งหนึ่งที่ฉันทำในขณะที่เตรียมโครงการ 5.1 ก่อนที่จะย้ายไปยัง 5.2
Gras Double

นี่เป็นคำตอบที่ยอดเยี่ยมมาก ถ้าฉันชอบคำตอบฉันจะ!
mwallisch

18

ในLaravel 4 และ 5order_byจะถูกแทนที่ด้วยorderBy

ดังนั้นควร:

User::orderBy(DB::raw('RAND()'))->get();

ผู้ใช้ :: orderBy (DB :: ดิบ ( 'RAND ()')) -> ได้รับ ();
Darius

1
มันใช้งานได้ดี แต่คุณสามารถให้ข้อมูลว่ามันทำงานอย่างไร
alayli

คุณจะเจาะจงเจาะจงมากกว่านี้ได้ไหม? ข้อมูลประเภทใด
Teodor Talov


9

สำหรับ Laravel 5.2> =

ใช้วิธี Eloquent:

inRandomOrder()

อาจใช้วิธีการ inRandomOrder เพื่อเรียงลำดับผลลัพธ์แบบสอบถามโดยการสุ่ม ตัวอย่างเช่นคุณอาจใช้วิธีนี้เพื่อดึงข้อมูลผู้ใช้แบบสุ่ม:

$randomUser = DB::table('users')
            ->inRandomOrder()
            ->first();

จากเอกสาร: https://laravel.com/docs/5.2/queries#ordering-grouping-limit-and-offset


หลักสูตร :: inRandomOrder () -> ใช้ (20) -> ได้รับ (); ไม่ทำงานสำหรับฉัน - ข้อมูลจำเพาะเกี่ยวกับการเรียงลำดับที่ไม่ดีใน Find.php บรรทัด 219
MJ

1
สิ่งนี้มีประโยชน์สำหรับโรงงานตัวอย่างหรือการสร้างฐานข้อมูล
Saleh Mahmood

8

คุณยังสามารถใช้วิธี order_by อย่างคล่องแคล่วและมีคารมคมคายเช่น:

Posts::where_status(1)->order_by(DB::raw(''),DB::raw('RAND()')); 

นี่เป็นการใช้งานที่แปลกเล็กน้อย แต่ใช้งานได้

แก้ไข: ดังที่ @Alex กล่าวว่าการใช้งานนี้สะอาดและใช้งานได้:

Posts::where_status(1)->order_by(DB::raw('RAND()'));

3
ทำงานได้ดีและสะอาดขึ้นเล็กน้อย .. -> order_by (\ DB :: raw ('RAND ()')))
Alex Naspo


3

คุณสามารถใช้คำสั่งนี้:

// คำถาม: ชื่อรุ่น
// จด 10 แถวจาก DB In shuffle records ...

$questions = Question::orderByRaw('RAND()')->take(10)->get();


3

Laravel มีวิธีการในตัวเพื่อสลับลำดับของผลลัพธ์

นี่คือคำพูดจากเอกสาร:

shuffle()

วิธีการสุ่มแบบสุ่มจะเป็นการสับรายการในคอลเลคชั่น:

$collection = collect([1, 2, 3, 4, 5]);

$shuffled = $collection->shuffle();

$shuffled->all();

// [3, 2, 5, 1, 4] - (generated randomly)

คุณสามารถดู เอกสารที่นี่


2

ในแบบจำลองของคุณให้เพิ่มสิ่งนี้:

public function scopeRandomize($query, $limit = 3, $exclude = [])
{
    $query = $query->whereRaw('RAND()<(SELECT ((?/COUNT(*))*10) FROM `products`)', [$limit])->orderByRaw('RAND()')->limit($limit);
    if (!empty($exclude)) {
        $query = $query->whereNotIn('id', $exclude);
    }
    return $query;
}

แล้วที่เส้นทาง / ตัวควบคุม

$data = YourModel::randomize(8)->get();

2

นอกจากนี้ยังมีwhereRaw('RAND()')ที่ไม่เหมือนกันแล้วคุณสามารถห่วงโซ่->get()หรือหรือแม้กระทั่งไปบ้าและเพิ่ม->first()->paginate(int)


0

ฉันมีตารางที่มีหลายพันระเบียนดังนั้นฉันต้องการบางสิ่งที่รวดเร็ว นี่คือรหัสของฉันสำหรับแถวสุ่มหลอก:

// count all rows with flag active = 1
$count = MyModel::where('active', '=', '1')->count(); 

// get random id
$random_id = rand(1, $count - 1);  

// get first record after random id
$data = MyModel::where('active', '=', '1')->where('id', '>', $random_id)->take(1)->first(); 

ปัญหานี้คือว่าถ้ามีหลายแถวที่มีรหัสที่มากกว่ารหัส$countแรกเท่านั้นที่จะถูกเรียกคืนและดังนั้นจึงมีแนวโน้มที่จะถูกเรียกคืนมากกว่าแถวอื่น ๆ
kemika
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.