donglv9813 2016-11-04 08:39
浏览 257
已采纳

Laravel - 按关系对象的属性对集合数组进行排序

I have two tables magazines with a field product_code, and another table issues. They have belongsToMany relationship.

Magazine model:

 public function issues()
 {
     return $this->hasMany('App\Issue');
 }

Issue model:

public function magazine()
{
    return $this->belongsTo('App\Magazine');
}

Currently I have a query where I get collections of issues grouped by magazine id and ordered by the date of the last issue.

$issues = Issue::orderBy('date', 'desc')->get()->groupBy('magazine_id');

This is how the result of my query looks like:

Collection {#431 ▼
  #items: array:23 [▼
    103 => Collection {#206 ▼
      #items: array:52 [▶]
    }
    106 => Collection {#216 ▶}
    124 => Collection {#452 ▶}
    112 => Collection {#451 ▶}
    115 => Collection {#450 ▶}
    123 => Collection {#449 ▶}
    107 => Collection {#448 ▶}
    113 => Collection {#447 ▶}
    117 => Collection {#446 ▶}
    109 => Collection {#445 ▶}
    110 => Collection {#444 ▶}
    121 => Collection {#443 ▶}
    120 => Collection {#442 ▶}
    114 => Collection {#441 ▶}
    116 => Collection {#440 ▶}
    118 => Collection {#439 ▶}
    126 => Collection {#438 ▶}
    125 => Collection {#437 ▶}
    119 => Collection {#436 ▶}
    122 => Collection {#435 ▶}
    105 => Collection {#434 ▶}
    111 => Collection {#433 ▶}
    104 => Collection {#432 ▶}
  ]
}

So, since I have 24 magazines, there are 24 collections of issues in the array, and each collection of issues belongs to one magazine. The collections are sorted by the date of the latests issue of each collection and issues inside of each collection are ordered by date as well. So, first collection in the array will be the one which has the latest issue in the table issues, the second collection will be the one which has the second latest issue in the same table and so on.

Since I will get an array of users subscriptions, which will consist of product codes like this:

$productCodes = ['aa1', 'bb2', 'cc3'];

I need to expand this query and sort the collections further by the $productCodes array that I will get. I need to check the codes from the productCodes array in the table magazines where I have the product_code field. The collections of issues grouped by magazine, should be then sorted so that the first collections are the ones whose magazine that they belong to has the same product_code as the code in the array productCodes, and amongst them, the first one would be whose collection has the latest issue by date. Then the rest of the collections should just be sorted by date. How can I make this kind of query?

Update

I have tried with a suggested code from @Paul Spiegel in the answers, and now I get an array of collections, with the collections of magazine issues. Issues in each magazine collection are ordered by date, and magazine collections that have the same product_code as in the $productCodes array are at the beginning of the array, but the the array of magazine collections is still not sorted by the date of the latest issue from each of the magazine collections.

  • 写回答

3条回答 默认 最新

  • dqb14659 2016-11-06 22:00
    关注

    First of all: Instead of using Collection::groupBy() you can just use relations:

    $magazines = Magazine::with(['issues' => function($query) {
        $query->orderBy('date', 'desc');
    }]);
    

    This will give you a collection of Magazines including related issues in an array. The issues array is sorted by date desc.

    Now you can split the result using two queries with different conditions:

    $baseQuery = Magazine::with(['issues' => function($query) {
        $query->orderBy('date', 'desc');
    }]);
    
    $query1 = clone $baseQuery;
    $query2 = clone $baseQuery;
    
    $query1->whereIn('product_code', $productCodes);
    $query2->whereNotIn('product_code', $productCodes);
    

    $query1 will return all magazines with product_code from the array. $query2 will return all the other magazines.

    You have now two ways to combine the two results:

    1) Use Eloquent::unionAll()

    $unionQuery = $query1->unionAll($query2);
    $magazines = $unionQuery->get();
    

    2) Use Collection::merge()

    $magazines1 = $query1->get();
    $magazines2 = $query2->get();
    $magazines = $magazines1->merge($magazines2);
    

    In both cases you will get the same result: A collection of magazines. The magazines with product_code from the $productCodes array are sorted first. Every Magazine object contains an array issues with related Issue objects.

    If you want to get rid of the Magazine objects and really need the result to look like in your question, you can still do:

    $issues = $magazines->keyBy('id')->pluck('issue');
    

    But there is probably no need for that.

    Update

    If you really need the two parts of the Magazine collection to be sorted by the latest Issue.. I don't see any way without using a JOIN or sorting in PHP with a closure. Sorting magazines with a join would also need an aggregation. So i would switch back to your original query extending it with a join and split it in two parts as showed above:

    $baseQuery = Issue::join('magazines', 'magazines.id', '=', 'issues.magazine_id');
    $baseQuery->orderBy('issues.date', 'desc');
    $baseQuery->select('issues.*');
    
    $query1 = clone $baseQuery;
    $query2 = clone $baseQuery;
    
    $query1->whereIn('magazines.product_code', $productCodes);
    $query2->whereNotIn('magazines.product_code', $productCodes);
    

    And then

    $issues1 = $query1->get()->groupBy('magazine_id');
    $issues2 = $query2->get()->groupBy('magazine_id');
    
    $issues = $issues1->union($issues2);
    

    or

    $issues = $query1->unionAll($query2)->get()->groupBy('optionGroupId');
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 2024-五一综合模拟赛
  • ¥15 如何将下列的“无限压缩存储器”设计出来
  • ¥15 下图接收小电路,谁知道原理
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口