2015-04-11 2 views
4

Я использую MiniMongo через Meteor, и я пытаюсь создать частотную таблицу, основанную на динамическом наборе запросов.Динамическая карта частоты от ключей MongoDB

У меня есть два основных поля: localHour и localDay. Я ожидаю много перекрытий, и я хотел бы определить, где происходит большинство перекрытий. Мой текущий способ сделать это так.

if(TempStats.findOne({ 
      localHour: hours, 
      localDay: day 
      })){//checks if there is already some entry on the same day/hour 

      TempStats.update({//if so, we just increment frequency 
       localHour: hours, 
       localDay: day 
      },{ 
       $inc: {freq: 1} 
      }) 

      } else {//if nothing exists yet, we put in a new entry 

      TempStats.insert({ 
       localHour: hours, 
       localDay: day, 
       freq: 1 
      }); 

      } 

По существу, этот код запускается каждый раз, когда у меня есть новые данные, которые я хочу вставить. Он отлично работает в данный момент, тем самым, после ввода всех данных, я могу сортировать по частоте, чтобы найти то, что чаще всего встречается & дней (TempStats.find({}, {sort: {freq: -1}}).fetch()).

Однако я ищу больше для поиска по частоте для любого ключа. Например, поиск дня, где все происходит чаще всего, в отличие от даты и часа. С моим нынешним способом сделать это, мне нужно будет иметь несколько баз данных и различные методы вставки для каждого, что немного смешно. Есть ли решение Mongo (в частности MiniMongo) для создания частотных карт на основе ключей?

Спасибо!

ответ

1

Это в основном простая проблема с уменьшением карты.

Во-первых, не разделяйте полученные данные на 2 поля. Это нарушает лучшие практики БД. Если данные поступают к вам таким образом, используйте его для создания объекта Date. Я предполагаю, что у вас есть куча коллекций, на которые подписаны, и затем вы объединяете все это в эту временную локальную коллекцию. Это отображение шаблона сокращения карты. На данный момент, поскольку ваш запрос неизвестен, это пустая трата процессора (даже если это ваш клиент) для объединения. Сначала выберите вторую. То, что вам нужно, - это коллекция, полная времени. назовите это TempMapCollection если хотите. Теперь используйте forEach() и передайте функцию уменьшения (по дням, часам и т. Д.).

Вы можете свернуть в другую локальную коллекцию или в объект javascript. Мне нравится использовать коллекции, но если объекты сложны, вы получите все ошибки EJSON. Поскольку ваши объекты не более чем datetime, давайте использовать коллекции.

так у вас есть что-то вроде:

TempMapCollection.find().forEach(function(doc) { 
    var date = doc.dateTime.getDate(); 
    TempReduceCollection.upsert({timequery: hours}, {$inc: {freq: 1}}); 
}) 

Теперь опрашивать сократить коллекцию. Это имеет дополнительное преимущество, которое вам не нужно будет перегруппировать, если вы хотите сделать 2 уникальных запроса.

+0

Спасибо за помощь! Отличный ответ. – mjkaufer

2
  1. небольшая заметка на вашем коде: та часть, которая приходит как-то заявление на самом деле не требуется ваше обновление будет делать полную работу, если объединить его с опцией upsert = верно, то это будет вставить новый документ и $inc будет устанавливать поле частоты в 1 по желанию: here и here
  2. для альтернативных способов подсчета частот: если вы храните дату как объект datetime, я бы предложил использовать агрегацию (я не уверен, что они добавили поддержку для агрегации еще в minimongo), но есть solutions, тогда с агрегацией вы можете использовать операторы datetime как $hour, $week, etc для фильтрации nd $ count, чтобы подсчитать частоты без необходимости вести подсчет в базе данных.
3

Похоже, что miniMongo на самом деле не поддерживает агрегацию, что затрудняет эту операцию. Один из способов сделать это - объединить себя в конце каждого дня и вставить эту совокупную запись в свой дБ (без поля часа или с ним установить что-то вроде -1). И наоборот, вы можете также обновить эту запись во время каждой вставки. Это позволит вам использовать одну и ту же коллекцию для обоих и достаточно распространена в других dbs.

Также вы должны рассмотреть первое предложение @ nickmilon, поскольку использование выражения upsert с оператором $ inc приведет к уменьшению вашего примера до одной операции на каждую точку данных.

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