группировать по запросам по сбору метеоров

Мои данные mongoDB:

>db.CUSTOMER.find()

{"Name": "A", "CreatedDate": "Wed Jan 29 2014"}

{"Name": "B", "CreatedDate": "Fri Jan 31 2014"}

{"Name": "C", "CreatedDate": "Sat Feb 01 2014"}

{"Name": "D", "CreatedDate": "Sat Feb 01 2014"}

В метеоре:

Customer = new Meteor.Collection("CUSTOMER");

Я пытаюсь сгруппировать их по дате (понедельник, вторник, среда, ...) в коллекции метеоров вместе с общим количеством данных. Это должно быть что-то вроде этого:

{"Date": "Wed Jan 29 2014", "Total" 1}

{"Date": "Fri Jan 31 2014", "Total" 1}

{"Date": "Sat Feb 01 2014", "Total" 2}

В mongoDB я бы просто использовал http://docs.mongodb.org/manual/reference/method/db.collection.group/, но, видимо, в метеоре это невозможно, так как он не поддерживает функции findAndModify, upsert, агрегат и map/reduce.

Есть ли примеры обходного пути, который я могу сделать, чтобы он работал?

Спасибо


person shihandrana    schedule 11.02.2014    source источник
comment
Отсутствие поддержки метеоров, о которой вы упоминаете, является клиентской стороной браузера. Вы можете выполнять операции на стороне сервера. Смотрите ответ.   -  person Neil Lunn    schedule 11.02.2014


Ответы (4)


Вам нужно будет сгруппировать их вручную. Есть несколько способов сделать это, но вот пример (правда, трудный для чтения):

var customers = Customer.find().fetch();

var groupedDates = _.groupBy(_.pluck(customers, 'CreatedDate'));

_.each(_.values(groupedDates), function(dates) {
  console.log({Date: dates[0], Total: dates.length});
});
person David Weldon    schedule 11.02.2014
comment
Спасибо, работает красиво. И это приводит к другому вопросу: кажется, что этот ответ группирует данные на основе различий CreatedDate. Если я хочу сгруппировать его еженедельно, ежемесячно или ежегодно (например), возможно ли это? - person shihandrana; 11.02.2014
comment
Конечно, вы можете просто указать второй аргумент для groupBy, например function(date){ return Date.split()[1]; } (это предполагает, что ваши даты являются строками — измените как необходимо для объектов даты). Также обратите внимание на ответ Flying Fisher с countBy - та же идея. - person David Weldon; 11.02.2014
comment
Разве это решение не медленное? Вы предлагаете подписаться на всю коллекцию в клиенте, а затем сделать _.groupBy? - person Jaro; 27.03.2015
comment
Имейте в виду, что как только вы возвращаете массив, вы теряете большой бонус прямой итерации курсора: каждый раз, когда ваши данные изменяются, весь ваш шаблон перерисовывается, а не только измененные данные. Если вы отображаете много данных в своем шаблоне, вам понадобится агрегация на уровне запроса. - person Loupax; 20.05.2015

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

Вы должны использовать aggregate а не функции mapReduce или group в большинстве случаев. Весь конвейер реализован на C++, а не передается на движок JavaScript. Во всех случаях эквивалентные функции в конвейере агрегации будут работать быстрее.

> db.dates.aggregate([
    {$group: { _id: {$dayOfWeek: "$CreatedDate"}, Total: {$sum: 1} }},
    {$project: { _id: 0, day: "$_id", Total: 1 } },
    {$sort: { day: 1 }}
  ])


  {
    "result" : [
            {
                    "Total" : 1,
                    "day" : 4
            },
            {
                    "Total" : 1,
                    "day" : 6
            },
            {
                    "Total" : 2,
                    "day" : 7
            }
    ],
    "ok" : 1
  }

О поддержке метеора

На стороне сервера метеор использует node-mongodb-native драйвер для всей обработки. Он поддерживается MongoDB и поддерживает все функции.

Клиентская сторона представляет собой библиотеку, известную как «мини-монго». На самом деле это не драйвер, а небольшой уровень, который на самом деле использует соединения сокетов для передачи данных на сервер. Это делает ваш javascript на стороне клиента «выглядящим» так же, как код на стороне сервера, но на самом деле вы не разговариваете с монго напрямую.

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

person Neil Lunn    schedule 11.02.2014

Я хочу добавить комментарий, но моя репутация слишком низкая. Просто используйте _.countBy может быть более читаемым.

_.countBy(customers,function(customer){return customer.CreatedDate}) Это должно вернуть dict ([CreatedDate]:count)

Надеюсь это поможет

person Flying Fisher    schedule 11.02.2014
comment
Пока я не могу получить или распечатать значение. Любые советы о том, как получить данные? - person shihandrana; 11.02.2014

Дополняю ответы выше:

  • вы не можете использовать все функции монго на клиенте, потому что метеор опирается на mini-mongo, который реализует только подмножество функций монго и не особенно эффективен. Таким образом, на клиенте вам лучше всего использовать некоторые функции подчеркивания, как описано @davidweldon. Из того, что я слышал, мини-монго также представляет собой набор функций подчеркивания и индексирует только идентификаторы.
  • вы по-прежнему можете использовать все функции монго на сервере, но это будет выглядеть немного хакерским, поскольку Meteor пытается скрыть их за своей оболочкой. Тем не менее, это, вероятно, намного эффективнее. Вот как это будет выглядеть:

.

mongoCustomer = Customer._collection.rawCollection() // you're now on the mongo realm

mongoCustomer.aggregate([
  {
    $group: {
      _id: "$CreatedDate",
      Total: { $sum: 1 }
    }
  }
], function(err, agg) {
  if (err) {
    ...
    return;
  }
  // agg an array of { CreatedDate, Total }, do what you want with it
});

Так что это хорошо, но вы также теряете синхронный синтаксис, который Meteor дает вам с Customer.find(...).fetch(). Теперь вы можете обернуть агрегацию монго в промис и использовать await/async, если хотите вернуть этот синтаксис.

person Guig    schedule 20.09.2016