将相关的模型集合数组替换为新的格式化数组

Posted

技术标签:

【中文标题】将相关的模型集合数组替换为新的格式化数组【英文标题】:Replace the related model collection array with a new formatted one 【发布时间】:2020-07-14 06:20:35 【问题描述】:

我有一个orderlamplamp_order 表。目前我获取订单和它的灯关系。我还像这样获取与灯相关的图像:

 $orders = Order::with('lamps.image')->get();

我计算一盏灯与按房间分组的订单相关的次数,如下所示:

$lamps = DB::table('lamp_order')
            ->where('order_id', $order->id)
            ->select('lamp_id', 'order_id', 'room', DB::raw('count(*) as total'))
            ->groupBy('room')
            ->groupBy('lamp_id')
            ->get();

我现在想将计数和房间名称添加到 Lamp 集合中,所以我这样做了:

$foundLamp = Lamp::find($lamp->lamp_id);
            $collection = collect($foundLamp);
            $collection->put('count', $lamp->total);
            $collection->put('room', $lamp->room);
            $formattedLampsArray[] = $collection;

如何将Order 中的相关Lamp 集合替换为我刚刚格式化的新集合?这是整个功能:

  public function index()
    
        // Fetch orders with their relationships relationships. 
        $orders = Order::with('lamps.image')->get();

        foreach ($orders as $order) 
            $lamps = DB::table('lamp_order')
                ->where('order_id', $order->id)
                ->select('lamp_id', 'order_id', 'room', DB::raw('count(*) as total'))
                ->groupBy('room')
                ->groupBy('lamp_id')
                ->get();

            $formattedLampsArray = [];

            foreach ($lamps as $lamp) 
                $foundLamp = Lamp::find($lamp->lamp_id);
                $collection = collect($foundLamp);
                $collection->put('count', $lamp->total);
                $collection->put('room', $lamp->room);
                $formattedLampsArray[] = $collection;
            
        

        return response()->json([
            'orders' => $orders
        ], 200);
    

基本上我现在想将$formattedLampsArray 添加到每个$order。所以我可以很容易地在前端为每个订单获取新的格式化相关灯。有谁知道我如何用新灯“更换”灯?

结果最好是这样的:

'id' => 1,
'name' => 'John Doe'
'email' => 'johndoe@gmail.com'
'notes' => 'Lorem ipsum dolor sit amet'
'created_at' => '2020-04-02 12:32:30' 
'updated_at' => '2020-04-02 12:32:30'
'lamps_count' => 20
'grouped_lamps' => [
  [
   'id' => 9
   'name' => 'Lamp 1'
   'fitting' => 'E14'
   'shape' => 'Candle'
   'room' => 'Hall'
   'count' => '5'
  ],
  [
   'id' => 9
   'name' => 'Lamp 1'
   'fitting' => 'E14'
   'shape' => 'Candle'
   'room' => 'Kitchen'
   'count' => '5'
  ],
  [
   'id' => 11
   'name' => 'Lamp 2'
   'fitting' => 'E27'
   'shape' => 'Pear'
   'room' => 'Livingroom'
   'count' => '5'
  ],
  [
   'id' => 12
   'name' => 'Lamp 3'
   'fitting' => 'E27'
   'shape' => 'Pear'
   'room' => 'Sleepingroom'
   'count' => '5'
  ],
];

【问题讨论】:

【参考方案1】:

The answer of AH.Pooladvand 帮助我朝着正确的方向前进,但它不符合我的要求。这就是为什么我仍然给它+50赏金奖。我的一个朋友告诉我,我应该直接查询数据透视表。我将这两个答案合并到这段代码中。

我需要提一下,它还没有效率,当我有完整的答案时,我会在这里发布。但我想发布这个来帮助其他人 与此同时。

   public function index()
    

        // Get all Orders and count the amount of related Lamps.
        $orders = Order::withCount('lamps')
            ->with('lamps.image') // Also fetch related Image of the Lamp
            ->get()
            ->map(static function (Order $order) 
                // For each lamp count how many times it occurs per room.
                $order->lamps->each(static function (Lamp $lamp) 
                    $countedLamps = DB::table('lamp_order')
                        ->select(DB::raw('*, count(*) as count_lamps'))
                        ->groupBy('lamp_id', 'room')
                        ->get();

                    foreach ($countedLamps as $countedLamp) 
                        // If lamp_id and room are the same then add the count and room to the Lamp. 
                        if ($countedLamp->lamp_id == $lamp['id'] && $countedLamp->room == $lamp['pivot']['room']) 
                            $lamp->count = $countedLamp->count_lamps;
                            $lamp->room = $countedLamp->room;
                        
                    
                );

                // Remove duplicate Lamps an create an new attribute in the collection array.
                $collection = collect($order->lamps);
                $order->ordered_lamps = $collection->unique()->values()->all();
                // Make unordered Lamps array hidden.
                $order->makeHidden('lamps');
                return $order;
            );

        return response()->json([
            'orders' => $orders,
        ], 200);
    

我获取所有订单,立即计算该订单中的灯数量并获取该灯的相关图像。对于每个订单,我按roomlamp_id 计算灯数。对于每个$groupedLamp,我都会进行脏检查,将计数和房间变量添加到lamp 对象本身。然后最后我从lamp 数组中删除重复项,将其隐藏并创建一个order_lamps 变量。欢迎任何改进。我会在优化后编辑这个答案。

【讨论】:

【参考方案2】:

我想这就是你要找的 有一个 withCount() 方法可以为您完成 ->select('lamp_id', 'order_id', 'room', DB::raw('count(*) as total')) 工作https://laravel.com/docs/5.8/eloquent-relationships#counting-related-models

请注意,因为->lamps 属性实际上是一个关系,所以我们无法对其进行变异,因此我们将其隐藏并创建一个名为grouped_lamps 的新属性

public function index()

    $orders = Order::withCount('lamps')
        ->with('lamps.image')
        ->get()->map(static function (Order $order) 
            $order->lamps->each(static function (Lamp $lamp) 
                $lamp->room = $lamp['pivot']['room'];
            );

            return $order;
        )->each(function (Order $order) 
            $order->grouped_lamps = $order->lamps->groupBy(['room', 'id']);
            $order->makeHidden('lamps');

            return $order;
        );

    return response()->json([
        'orders' => $orders,
    ], 200);

编辑

我不确定这是否是你要找的,但我们开始吧

首先,我们需要使用我们的关系获取额外的 room 列,因此请确保在您的 Order 模型中添加 ->withPivot('room') 像这样

public function lamps()

    return $this->belongsToMany(Lamp::class, 'lamp_order', 'lamp_id', 'order_id')
        ->withPivot('room');

这里是代码,我们不再需要grouped_lamps

public function index()

    $orders = Order::withCount('lamps')
        ->with('lamps.image')
        ->get()->map(function (Order $order) 
            $order->lamps->each(static function (Lamp $lamp) use ($order) 
                $lamp->room = $lamp['pivot']['room'];
                $lamp->count = $order->lamps_count;
            );

            return $order;
        );

    return response()->json([
        'orders' => $orders,
    ], 200);

希望对你有帮助

最终编辑 好的,通过查看我的代码,我发现我犯了一个诚实的错误

灯具关系foreign_keylocal_key 位置错误,这是正确的形式

public function lamps()

    return $this->belongsToMany(Lamp::class, 'lamp_order', 'order_id', 'lamp_id')
        ->withPivot('room');

这是新版本的代码请注意,如果您对以前的格式没问题,则无需使用以下代码

public function index()

    $orders = Order::withCount('lamps')
        ->with('lamps.image')
        ->get()
        ->map(static function (Order $order) 
            $order->lamps->each(static function (Lamp $lamp) 
                $lamp->room = $lamp['pivot']['room'];
            );

            return $order;
        )->each(function (Order $order) 
            $groupedLamps = $order->lamps->groupBy('room');
            $order->lamps->each(function (Lamp $lamp) use ($groupedLamps) 
                $lamp->count = $groupedLamps[$lamp->room]->count();
            );
        );

    return response()->json([
        'orders' => $orders,
    ], 200);

你会得到这样的结果


    "orders": [
        
            "id": 1,
            "title": "ut fugit facilis",
            "lamps_count": 5, // Total lamps owned by this order
            "lamps": [
                
                    "title": "ab sunt nostrum",
                    "room": "kitchen",
                    "count": 3, // Total number of kitchen lamps of order_id 1
                    "pivot": 
                        "order_id": 1,
                        "lamp_id": 1,
                        "room": "kitchen"
                    
                ,
                
                    "title": "omnis dicta rerum",
                    "room": "hall",
                    "count": 2, // Total number of hall lamps of order_id 1
                    "pivot": 
                        "order_id": 1,
                        "lamp_id": 2,
                        "room": "hall"
                    
                ,
                
                    "title": "eligendi deserunt et",
                    "room": "hall",
                    "count": 2, // Total number of hall lamps of order_id 1
                    "pivot": 
                        "order_id": 1,
                        "lamp_id": 3,
                        "room": "hall"
                    
                ,
                
                    "title": "modi ad ea",
                    "room": "kitchen",
                    "count": 3, // Total number of kitchen lamps of order_id 1
                    "pivot": 
                        "order_id": 1,
                        "lamp_id": 4,
                        "room": "kitchen"
                    
                ,
                
                    "title": "eos neque consequatur",
                    "room": "kitchen",
                    "count": 3, // Total number of kitchen lamps of order_id 1
                    "pivot": 
                        "order_id": 1,
                        "lamp_id": 5,
                        "room": "kitchen"
                    
                
            ]
        ,
        
            "id": 2,
            "title": "sapiente velit quas",
            "lamps_count": 2,
            "lamps": [
                
                    "title": "eligendi deserunt et",
                    "room": "kitchen",
                    "count": 2,
                    "pivot": 
                        "order_id": 2,
                        "lamp_id": 3,
                        "room": "kitchen"
                    
                ,
                
                    "title": "modi ad ea",
                    "room": "kitchen",
                    "count": 2,
                    "pivot": 
                        "order_id": 2,
                        "lamp_id": 4,
                        "room": "kitchen"
                    
                
            ]
        ,
        
            "id": 3,
            "title": "itaque sint voluptas",
            "lamps_count": 4,
            "lamps": [
                
                    "title": "omnis dicta rerum",
                    "room": "kitchen",
                    "count": 1,
                    "pivot": 
                        "order_id": 3,
                        "lamp_id": 2,
                        "room": "kitchen"
                    
                ,
                
                    "title": "eligendi deserunt et",
                    "room": "living_room",
                    "count": 1,
                    "pivot": 
                        "order_id": 3,
                        "lamp_id": 3,
                        "room": "living_room"
                    
                ,
                
                    "title": "modi ad ea",
                    "room": "hall",
                    "count": 2,
                    "pivot": 
                        "order_id": 3,
                        "lamp_id": 4,
                        "room": "hall"
                    
                ,
                
                    "title": "eos neque consequatur",
                    "room": "hall",
                    "count": 2,
                    "pivot": 
                        "order_id": 3,
                        "lamp_id": 5,
                        "room": "hall"
                    
                
            ]
        
    ]

【讨论】:

首先感谢您的回答,这几乎是我想要的。困难的部分是分组的灯现在显示在我的 Vue.js 前端,如下所示:grouped_lamps: Kitchen: [...], Livingroom: [...] 这使得迭代变得困难,因为我想在表格中显示它们。在这张表中,我想显示灯在哪个房间。是否可以在 grouped_lamps 对象中添加所有灯,添加房间和这些灯的数量,并删除重复项。所以我只为每个房间的每盏灯拿一个并显示它的数量? @Baspa 你能给我一个数据集的例子吗? 对我来说模糊的是,您到底想要什么灯关系... @Baspa 更新了我的答案,请查看最终编辑部分 @AH.Pooladvand 感谢您使用edit 功能为您的帖子提供更多信息。但请不要用EDIT:UPDATE: 部分污染您的帖子。 For future readers, posts need to be standalone, without any history. These sites are not forums, but intend to be libraries of canonical, high-quality, questions and answers. Future readers are not helped by seeing all kind of history.

以上是关于将相关的模型集合数组替换为新的格式化数组的主要内容,如果未能解决你的问题,请参考以下文章

如何将字符串数组拆分为新的字符串数组并删除重复项

Laravel API resourceCollection 使用数组而不是模型

如何在隐藏输入字段中保存数组的值,然后再将其替换为新数组

Vuexfire serialize 选项未正确格式化数组

PHP array_chunk() 函数把数组分割为新的数组块

React JS concat数组并转换为新的二维数组并按二维数组数据和排序