2015-05-21 1 views
6

Имея некоторые проблемы, разработанные наилучшим способом сделать это в MongoDB, возможно, это набор данных отношений, поэтому я, вероятно, буду называться. Тем не менее его задача - проверить, возможно ли это.MongoDB Сортировка по средним комбинированным номерам или вложенным вспомогательным массивам

В настоящее время мне необходимо заказать ежедневные среднемировые милиции менеджеров по логистике через микроавтобусы в своем отделе, а также в отдельном списке комбинированное недельное среднее.

Г-н Первая установка в базе данных следующим образом

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

Но я не могу понять, как сделать заказ вложенным значения массива, не зная ключа родительского массива (это будет стандартный 0-х)

Таким образом, мой следующий выбор заключался в том, чтобы отказаться от этой идеи, просто получив имя в первой коллекции и в фургонах во второй коллекции с Id менеджера.

Поэтому удаление фургонов из приведенного выше примера и добавление этой коллекции (фургоны)

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

Но поскольку мне нужно показать результаты от менеджера, как сделать заказ в запросе (если возможно) средний миль эта коллекция, где id = x, а затем отображает менеджера по его идентификатору.

Спасибо за вашу помощь

ответ

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 имеет временную метку, но это отражает только время создания документа, не обязательно время журнала начального дня.

Вопросы для первой модели данных:

  • представляют ли каждый документ один день или один менеджер?
  • Сколько «фургонов» вы ожидаете иметь в массиве? Со временем этот список растет? Вам нужно рассмотреть размер документа размером до 16 МБ через год или два?

Вопросы для второй модели данных:

  • Вы можете хранить имя менеджера, как «manager_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 
    } } 
]); 

Если для первой модели данных, каждый документ представляет собой менеджер и «фургоны» массив растет ежедневно, эта конкретная модель данных не является идеальным по двум причинам:

  • «фургоны» массив может вырасти за пределы максимального размера документа ... в конце концов, несмотря на то, что было бы намного данных
  • Труднее и большой объем памяти, чтобы ограничить определенный диапазон дат, так как метка времени в этот момент будет вложен в пределах пункта «фургонов», а не в корне документа

Для полноты картины здесь запрос:

/* 
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

Смежные вопросы