按多个字段分组然后生成总和

时间:2017-11-25 10:31:49

标签: php arrays laravel collections laravel-5.2

我有一个基于Laravel 5.2的配方构建应用程序。

用户可以在食谱中添加成分,偶尔也可以添加两次相同的成分,具体取决于您使用的成分。

我正在构建允许用户为其食谱生成购物清单的功能,这应该为他们生成PDF购物清单。

到目前为止,我已经列出了生成的成分列表,但我无法完全了解如何进行分组和总结金额。

典型的列表可能如下所示:

[  
   {  
      "id":97724,
      "name":"Citra Pellets",
      "amount":6.5,
      "hop_type_id":"Pellet",
      "recipe_id":23453
   },
   {  
      "id":97725,
      "name":"Simcoe Pellets",
      "amount":6.5,
      "hop_type_id":"Pellet",
      "recipe_id":23453
   },
   {  
      "id":97726,
      "name":"Citra Pellets",
      "amount":6.5,
      "hop_type_id":"Pellet",
      "recipe_id":23453
   },
   {  
      "id":97727,
      "name":"Simcoe Pellets",
      "amount":6.5,
      "hop_type_id":"Pellet",
      "recipe_id":23453
   },
   {  
      "id":97729,
      "name":"Mosaic Pellets",
      "amount":79.9999,
      "hop_type_id":"Pellet",
      "recipe_id":23453
   },
   {  
      "id":97730,
      "name":"Simcoe Pellets",
      "amount":60,
      "hop_type_id":"Combined",
      "recipe_id":23453
   }
]

目前,我只是在我的视图中有一个foreach循环,以吐出结果;出现这样的事情:

+--------+----------------+------------+
| Amount |      Name      | Usage Type |
+--------+----------------+------------+
|    6.5 | Citra Pellets  | Pellet     |
|    6.5 | Simcoe Pellets | Pellet     |
|    6.5 | Citra Pellets  | Pellet     |
|    6.5 | Simcoe Pellets | Pellet     |
|  79.99 | Mosaic Pellets | Pellet     |
|     60 | Simcoe Pellets | Combined   |
+--------+----------------+------------+

我想要做的是按照名称和使用类型对成分进行分组,然后获取金额的总和。所以输出是这样的:

+--------+----------------+------------+
| Amount |      Name      | Usage Type |
+--------+----------------+------------+
|     13 | Citra Pellets  | Pellet     |
|     13 | Simcoe Pellets | Pellet     |
|  79.99 | Mosaic Pellets | Pellet     |
|     60 | Simcoe Pellets | Combined   |
+--------+----------------+------------+

到目前为止,我的尝试包括App\Models\Recipe::find(23453)->hops->groupBy('name') - 这给了我类似下面的内容:

{  
   "Citra Pellets":[  
      {  
         "id":97724,
         "name":"Citra Pellets",
         "amount":6.5,
         "hop_type_id":"Pellet",
         "recipe_id":23453
      },
      {  
         "id":97726,
         "name":"Citra Pellets",
         "amount":6.5,
         "hop_type_id":"Pellet",
         "recipe_id":23453
      },
      {  
         "id":97728,
         "name":"Citra Pellets",
         "amount":94.9999,
         "hop_type_id":"Pellet",
         "recipe_id":23453
      }
   ],
   "Simcoe Pellets":[  
      {  
         "id":97725,
         "name":"Simcoe Pellets",
         "amount":6.5,
         "hop_type_id":"Pellet",
         "recipe_id":23453
      },
      {  
         "id":97727,
         "name":"Simcoe Pellets",
         "amount":6.5,
         "hop_type_id":"Pellet",
         "recipe_id":23453
      },
      {  
         "id":97730,
         "name":"Simcoe Pellets",
         "amount":60,
         "hop_type_id":"Combined,
         "recipe_id":23453
      }
   ],
   "Mosaic Pellets":[  
      {  
         "id":97729,
         "name":"Mosaic Pellets",
         "amount":79.9999,
         "hop_type_id":"Pellet",
         "recipe_id":23453
      }
   ]
}

这允许我循环遍历每个然后->sum('amount')以获得总和值。但是,它并没有考虑hop_type_id这一点很重要。

我也尝试将->groupBy('hop_type_id')链接起来,并使用->each(function ($item, $key))的变体但尚未成功解决此问题。

看起来集合上的初始groupBy()会生成一个键对象,其中包含一系列值。

我最理想的是每个hop_type_id的每个跃点名称下的另一个级别,然后我可以使用它来为每个跃点namehop_type_id生成总和。

我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:0)

我认为你正在寻找这个 -

\App\Ingredient::where('recipe_id','=',23453)->selectRaw('sum(amount) as amount, name, hop_type_id')->groupBy('name')->groupby('hop_type_id')->get();

希望有所帮助:)

答案 1 :(得分:0)

您可以将整个容器重写为一系列成分。这样,Recept对象的类型将是

     Ingredient[] 

每种成分都有以下私有字段和相应的公共getter

         $id, (string) $name, (int) $amount, $hop_type_id, $recipe_id

然后,您可以生成如下的购物清单

$shoppingList = [];
foreach($recept as $ingredient) {
    $shoppingList[$ingredient->getName()] += $ingredient->getAmount();
}