2015-04-09 2 views
0

Мои объекты имеют следующую структуру:Как рисовать и группировать в MongoDB?

{id: 1234, ownerId: 1, typeId: 3456, date:...} 
{id: 1235, ownerId: 1, typeId: 3456, date:...} 
{id: 1236, ownerId: 1, typeId: 12, date:...} 

Я хотел бы запросить базу данных таким образом, что он возвращает все элементы, которые принадлежат к данному ownerId, но только первый пункт данного typeId. IE поле typeId уникально в результатах. Я также хотел бы иметь возможность использовать skip и limit.

В SQL запрос будет что-то вроде:

SELECT * FROM table WHERE ownerId=1 SORT BY date GROUP BY typeId LIMIT 10 OFFSET 300

настоящее время у меня следующий запрос (с использованием PyMongo), но это дает мои ошибки для использования $sort, $limit и $skip:

search_dict['ownerId'] = 1 
search_dict['$sort'] = {'date': -1} 
search_dict['$limit'] = 10 
search_dict['$skip'] = 200 

collectionName.group(['typeId'], search_dict, {'list': []}, 'function(obj, prev) {prev.list.push(obj)}') 

-

Я также пробовал агрегацию ro но я понимаю, что группировка коснется всех элементов коллекции, сгруппирует их, а затем ограничит и пропустит. Это будет слишком дорогостоящим и медленным. Мне нужен итеративный алгоритм группировки.

search_dict = {'ownerId':1} 
collectionName.aggregate([ 
      { 
       '$match': search_dict 
      }, 
      { 
       '$sort': {'date': -1} 
      }, 
      { 
       '$group': {'_id': "$typeId"} 
      }, 
      { 
       '$skip': skip 
      }, 
      { 
       '$limit': 10 
      } 
     ]) 
+0

** Вопрос должен показать ваши усилия, чтобы решить проблему самостоятельно. **;) После этого я с радостью ответю. –

+0

Посмотрите на агрегат мангуста, попробуйте и вернитесь к нам :) –

+0

@RichardMacarthy: Почему мангуста? Довольно бесполезно, если OP - это Pythonista или Coffee Cup (как и я), не так ли? –

ответ

-2

Я не уверен, как вы понимаете, что эта операция должна быть дорогостоящей. Это не так для большинства баз данных SQL, и это, безусловно, не для MongoDB. Все, что вам нужно, это создать индекс по вашему критерию сортировки.

Вот как это доказать:

Открывают Монго оболочки и иметь это выполняется.

var bulk = db.speed.initializeOrderedBulkOp() 
for (var i = 1; i <= 100000; i++){ 
    bulk.insert({field1:i,field2:i*i,date:new ISODate()}); 
    if((i%100) == 0){print(i)} 
} 

bulk.execute(); 

Полное исполнение может занять определенное количество секунд. Затем мы создаем вспомогательную функцию:

Array.prototype.avg = function() { 
    var av = 0; 
    var cnt = 0; 
    var len = this.length; 
    for (var i = 0; i < len; i++) { 
    var e = +this[i]; 
    if(!e && this[i] !== 0 && this[i] !== '0') e--; 
    if (this[i] == e) {av += e; cnt++;} 
    } 
    return av/cnt; 
} 

Труппа готова, этап установлен:

var times = new Array(); 
for(var i = 0; i < 10000; i++){ 
    var start = new Date(); 
    db.speed.find().sort({date:-1}).skip(Math.random()*100000).limit(10); 
    times.push(new Date() - start); 
} 
print(times.avg() + " msecs"); 

Выход в msecs. Это выход из 5 трасс для сравнения:

  1. 0.1697 мсек
  2. 0.1441 мсек
  3. 0.1397 мсек
  4. 0.1682 мсек
  5. 0.1843 мсек

Тест сервер работает Внутри которое, в свою очередь, запускается внутри виртуальной машины (boot2docker) на моем 2,13 ГГц Intel Core 2 Duo с 4 ГБ оперативной памяти, работает OSX 10.10.2, много окон Safari, iTunes, Mai l, Spotify и Eclipse. Не совсем система производства. И эта коллекция даже не имеет индекса в поле даты. С индексом средние из 5 прогонов выглядят так:

  1. 0.1399
  2. мсек
  3. 0,1431 мс
  4. 0.1339 миллисекунды
  5. 0,1441 миллисекунды
  6. 0,1767 миллисекунды

ч.т.д., HTH.

+0

Ум, чтобы объяснить нисходящее, нисходящее? Просто любопытно и хочется улучшить. –

+0

@makuswmahlberg: Я не был тем, кто проголосовал за вас, но запрос в вашем тесте полностью отличается от моего запроса. Это потому, что вы не группируете. Повторите тест, и каждые 10 записей будут иметь одно и то же значение field2, а затем группу по полю2. Также попробуйте ввести 10 миллионов записей и случайных дат. 10 миллионов - это размер моей коллекции. – Jakobovski

+0

Несомненно, приспособит это, было только для демонстрационных целей. Создадим коллекцию сейчас, потребуется некоторое время, и здесь уже поздно (CEST). –

0

Ваше агрегирование выглядит правильно. Вам нужно указать нужные поля в выводе на этапе $group, используя $first.

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

Это не касается всех предметов в коллекции. Если совпадение + сортировка индексируется ({ "ownerId" : 1, "date" : -1 }), индекс будет использоваться для соответствия + сортировки, и группа будет обрабатывать только документы, являющиеся результатом совпадения.

Ограничение вряд ли когда-либо происходит, за исключением случаев неиндексированного сортировки. Обычно это дисковый ввод-вывод.

Мне нужен итеративный алгоритм группировки.

Что именно вы подразумеваете под «итеративной группировкой»? Группировка является итеративной, поскольку она выполняет итерацию по результатам предыдущего этапа и проверяет, к какой группе принадлежит каждый документ!

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