2015-05-21 40 views
6

在MongoDB中有一些問題找出最好的方法來處理這個問題,可以說它是一個關係數據集,所以我可能會這樣做。仍然是一個挑戰,看看它是否可能。MongoDB按平均組合數字或嵌套子陣列進行排序

我目前需要通過物流經理的部門每天的平均行駛里程數和單獨的列表中的每週平均值進行排序。

在數據庫

第一MR設置爲如下

{ 
    "_id" : ObjectId("555cf04fa3ed8cc2347b23d7"), 
    "name" : "My Manager 1", 
    "vans" : [ 
     { 
      "name" : "van1", 
      "miles" : NumberLong(56) 
     }, 
     { 
      "name" : "van2", 
      "miles" : NumberLong(34) 
     } 
    ] 
} 

但我不能看到如何通過嵌套數組值定購,而無需知道父陣列鍵(這些將是標準的0-X)

所以我的下一個選擇是廢除這個想法,只有第一個集合中的名稱和第二個集合中的貨車與經理的Id。

所以從上面的例子中刪除貨車和加入該集合(麪包車)

{ 
    "_id" : ObjectId("555cf04fa3ed8cc2347b23d9"), 
    "name" : "van1", 
    "miles" : NumberLong(56), 
    "manager_id" : "555cf04fa3ed8cc2347b23d7" 
} 

但是,因爲我需要證明由經理的結果,我怎麼在查詢命令(如果可能)的英里數平均這個集合,其中id = x,然後通過他的id顯示經理。

感謝您的幫助

回答

2

如果Manager將會有Van限量號碼,那麼你的第一種方法是更好,因爲你不必讓兩個單獨的呼叫/查詢數據庫收集您的信息。

然後問題如何計算每個Manager,其中Aggregation Framework將幫助你很多的平均空白。下面是一個查詢,將讓你想要的數據:

db.manager.aggregate([ 
         {$unwind: "$vans"}, 
         {$group: 
            {_id: 
             { 
              _id: "$_id", 
              name: "$name" 
             }, 
            avg_milage: {$avg: "$vans.miles"} 
            } 
         }, 
         {$sort: {"avg_milage": -1}}, 
         {$project: 
            {_id: "$_id._id", 
            name: "$_id.name", 
            avg_milage: "$avg_milage" 
            } 
         } 
        ]) 

第一$unwind一步只是解開了vans陣列,並建立針對陣列中的每個元素一個單獨的文件。

然後$group階段獲得具有相同(_id, name)對所有文件,並在avg_milage領域,統計miles場的平均值了這些文件的。

$sort階段很明顯,它只是按降序排列文檔,使用新的avg_milage字段作爲排序關鍵字。

最後,最後一步$project只是作出適當的預測清理的文件,只是爲了美容:)

需要類似的事情你的第二個理想的結果:

db.manager.aggregate([ 
         {$unwind: "$vans"}, 
         {$group: 
            {_id: 
             { 
              _id: "$_id", 
              name: "$name" 
             }, 
            total_milage: {$sum: "$vans.miles"} 
            } 
         }, 
         {$sort: {"total_milage": -1}}, 
         {$project: 
            {_id: "$_id._id", 
            name: "$_id.name", 
            weekly_milage: { 
                 $multiply: [ 
                    "$total_milage", 
                    7 
                    ] 
                } 

            } 
         } 
        ]) 

這將產生Managers與他們每週的青貯列表,按降序排列。所以,你可以$limit的結果,並得到Manager與最高的米蘭例如。

而且在幾乎同樣的方式,你可以抓住你的車的信息:

db.manager.aggregate([ 
         {$unwind: "$vans"}, 
         {$group: 
            {_id: "$vans.name", 
            total_milage: {$sum: "$vans.miles"} 
            } 
         }, 
         {$sort: {"total_milage": -1}}, 
         {$project: 
            {van_name: "$_id", 
            weekly_milage: { 
                 $multiply: [ 
                    "$total_milage", 
                    7 
                    ] 
                } 

            } 
         } 
        ]) 
+0

嗨,謝謝你的建議。我確實嘗試過,它的工作,但avg_mile返回是0.000? – deejuk

+0

有錯誤,更新了答案,再試一次:) – bagrat

+0

等待忘記刪除.miles中的$。這很有用,所以可以多謝你的幫助。幾英里呢? x 7,然後在列表中顯示,而不是平均值 – deejuk

1

首先,你需要平均里程數,單日平均里程在給定的時間段,或平均里程超過經理的生活?我會考慮添加時間戳字段。是的,_id有時間戳,但這隻反映文檔創建的時間,不一定是第一天的日誌時間。

注意事項的第一個數據模型:

  • 是否每個文件代表某一天,或者一個經理?
  • 你期望在陣列中有多少「貨車」?這個列表隨着時間的推移而增長嗎您是否需要在一兩年內考慮最大16MB的文檔大小?

考慮第二個數據模型:

  • 你可以存儲管理器的名稱爲「經理標識」領域?這可以用作次元查找的唯一ID嗎?這樣做會限制二級管理器元數據查找的必要性,以獲取其名稱。

由於@n9code has pointed out,聚合框架是兩種情況下的答案。

對於第一個數據模型中,假定每個文件代表一天,要檢索某一天的平均或天數範圍:

db.collection.aggregate([ 
    { $match: { 
     name: 'My Manager 1', 
     timestamp: { $gte: ISODate(...), $lt: ISODate(...) } 
    } }, 
    { $unwind: '$vans' }, 
    { $group: { 
     _id: { 
      _id: '$_id', 
      name: '$name', 
      timestamp: '$timestamp' 
     }, 
     avg_mileage: { 
      $avg: '$miles' 
     } 
    } }, 
    { $sort: { 
     avg_mileage: -1 
    } }, 
    { $project: { 
     _id: '$_id._id', 
     name: '$_id.name', 
     timestamp: '$_id.timestamp', 
     avg_mileage: 1 
    } } 
]); 

如果第一個數據模型,每個文檔代表經理和「車」陣列每天都在增長,這個特殊的數據模型是不理想的原因有兩個:

  • 「麪包車」數組可能增長超過最大文件大小......最終,儘管這將是一個很大的數據
  • 限制某個日期範圍更加困難和內存密集,因爲此時的時間戳將嵌套在「vans」項中而不是文檔根中

爲了完整起見,這裏是查詢:

/* 
Assuming data model is: 
{ 
    _id: ..., 
    name: ..., 
    vans: [ 
     { name: ..., miles: ..., timestamp: ... } 
    ] 
} 
*/ 

db.collection.aggregate([ 
    { $match: { 
     name: 'My Manager 1' 
    } }, 
    { $unwind: '$vans' }, 
    { $match: { 
     'vans.timestamp': { $gte: ISODate(...), $lt: ISODate(...) } 
    } }, 
    { $group: { 
     _id: { 
      _id: '$_id', 
      name: '$name' 
     }, 
     avg_mileage: { 
      $avg: '$miles' 
     } 
    } }, 
    { $sort: { 
     avg_mileage: -1 
    } }, 
    { $project: { 
     _id: '$_id._id', 
     name: '$_id.name', 
     avg_mileage: 1 
    } } 
]); 

對於第二個數據模型,聚合更直接。我假設包含一個時間戳:

db.collection.aggregate([ 
    { $match: { 
     manager_id: ObjectId('555cf04fa3ed8cc2347b23d7') 
     timestamp: { $gte: ISODate(...), $lt: ISODate(...) } 
    } }, 
    { $group: { 
     _id: '$manager_id' 
     }, 
     avg_mileage: { 
      $avg: '$miles' 
     } 
     names: { 
      $addToSet: '$name' 
     } 
    } }, 
    { $sort: { 
     avg_mileage: -1 
    } }, 
    { $project: { 
     manager_id: '$_id', 
     avg_mileage: 1 
     names: 1 
    } } 
]); 

我在平均計算過程中添加了一組名稱(車輛?)。

相關文章:

+0

欣賞你的幫助,以前的答案完美無缺 – deejuk