php – Laravel MongoDB 的 distinct 的 count() 用法
原因
官方提供的 distinct()
會在 php 取得所有列表。
$users = User::distinct()->get(['name']);
當要計算數量如果使用 count()
那會把資料全部撈到 php 然後加總,這會非常吃 php-fpm 所使用的記憶體。
$users = User::distinct()->get(['name'])->count();
改用聚合
讓 count()
這件事情在取出資料庫之前就完成,由資料庫回傳一個數值是最好的辦法。但現階段必須透過 laravel mongodb 的聚合寫法,以下範例示範:
1. 建立範例數據
db.test_orders.insertMany( [
{ _id: 0, name: "Pepperoni", size: "small", price: 19,
quantity: 10, date: ISODate( "2021-03-13T08:14:30Z" ) },
{ _id: 1, name: "Pepperoni", size: "medium", price: 20,
quantity: 20, date : ISODate( "2021-03-13T09:13:24Z" ) },
{ _id: 2, name: "Pepperoni", size: "large", price: 21,
quantity: 30, date : ISODate( "2021-03-17T09:22:12Z" ) },
{ _id: 3, name: "Cheese", size: "small", price: 12,
quantity: 15, date : ISODate( "2021-03-13T11:21:39.736Z" ) },
{ _id: 4, name: "Cheese", size: "medium", price: 13,
quantity:50, date : ISODate( "2022-01-12T21:23:13.331Z" ) },
{ _id: 5, name: "Cheese", size: "large", price: 14,
quantity: 10, date : ISODate( "2022-01-12T05:08:13Z" ) },
{ _id: 6, name: "Vegan", size: "small", price: 17,
quantity: 10, date : ISODate( "2021-01-13T05:08:13Z" ) },
{ _id: 7, name: "Vegan", size: "medium", price: 18,
quantity: 10, date : ISODate( "2021-01-13T05:10:13Z" ) }
] )

2. 使用聚合做到 distinct
假設我要知道 test_orders
裡面總共出現幾個 name
,那可以透過聚合的 pipeline 實現。先寫結論
db.test_orders.aggregate([
// 產生兩個欄位 _id 與 count,_id 指定分組的目標也就是欄位 name,count 則使用 $sum 去加總出現的數量
{ $group: { _id: "$name", count: { $sum: 1 } } },
// 將上方結果,再過濾,欄位一樣 _id 與 count,我們只需要加總出現的列表數量,即是達到我們的 distinct 需求
{ $group: { _id: 'total', count: { $sum: 1 } } }
])

這樣就達到我們要的目標 3 筆。
3. 肢解上述
上述 aggregate()
用了兩次處理,我們分開來看數據。第一次先算出各筆 name
的重複次數
db.test_orders.aggregate([
{ $group: { _id: "$name", count: { $sum: 1 } } },
])

看到這裡就知道這份數據,有 3 種 name
。因此可以這麼寫
db.test_orders.aggregate([
{ $group: { _id: "$name", count: { $sum: 1 } } },
{ $group: { _id:'total', count: { $sum: 1 } } }
])
