Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do mongo group on Meteor server side

Tags:

mongodb

meteor

On meteor mongo shell I can use db.collection.group but from Meteor.methods I can'd because Meteor don't support it.

How could I write a method which would do something similar to:

db.orders.group({
  keyf: function(doc) {return {year:doc.createdAt.toISOString().substring(0, 4)}},
  initial: {months:{}},
  reduce: function(order, result) {
    var month = order.createdAt.getMonth()+1,
        date = order.createdAt.getDate();

    month = result.months[month] || (result.months[month] = {});
    date = month[date] || (month[date] = []);
    date.push(order);
  },
  cond: {$and: [{createdAt: {$gt: new Date("2015-01-01")}, createdAt: {$lt: new Date("2015-12-31")}}]}
})

Expecting result is array of objects groups by month and then grouped by dates inside months.

P.S. orders, is quite big collection and I really want to do grouping in the database.


After information about rawCollection() in 1.0.4 I tried this:

  collection = Orders.rawCollection();
  params = {
    keyf: function(doc) {return {year:doc.createdAt.toISOString().substring(0, 4)}},
    initial: {months:{}},
    reduce: function(order, result) {
      var month = order.createdAt.getMonth()+1,
          date = order.createdAt.getDate();

      month = result.months[month] || (result.months[month] = {});
      date = month[date] || (month[date] = []);
      date.push(order);
    },
    cond: {$and: [{createdAt: {$gt: new Date("2015-01-01")}, createdAt: {$lt: new Date("2015-12-31")}}]}
  };
  Meteor.wrapAsync(collection.group, collection)(params);

I'm getting:

W20150327-13:26:24.924(2)? (STDERR) /Users/jaro/.meteor/packages/mongo/.1.1.0.1jqg8g6++os+web.browser+web.cordova/npm/node_modules/mongodb/lib/mongodb/connection/base.js:246
W20150327-13:26:24.924(2)? (STDERR)         throw message;      
W20150327-13:26:24.924(2)? (STDERR)               ^
W20150327-13:26:24.929(2)? (STDERR) TypeError: undefined is not a function
W20150327-13:26:24.929(2)? (STDERR)     at /Users/jaro/.meteor/packages/mongo/.1.1.0.1jqg8g6++os+web.browser+web.cordova/npm/node_modules/mongodb/lib/mongodb/collection/aggregation.js:229:22
W20150327-13:26:24.931(2)? (STDERR)     at /Users/jaro/.meteor/packages/mongo/.1.1.0.1jqg8g6++os+web.browser+web.cordova/npm/node_modules/mongodb/lib/mongodb/db.js:1191:22
W20150327-13:26:24.931(2)? (STDERR)     at /Users/jaro/.meteor/packages/mongo/.1.1.0.1jqg8g6++os+web.browser+web.cordova/npm/node_modules/mongodb/lib/mongodb/db.js:1903:9
W20150327-13:26:24.931(2)? (STDERR)     at [object Object].Base._callHandler (/Users/jaro/.meteor/packages/mongo/.1.1.0.1jqg8g6++os+web.browser+web.cordova/npm/node_modules/mongodb/lib/mongodb/connection/base.js:453:41)
W20150327-13:26:24.932(2)? (STDERR)     at /Users/jaro/.meteor/packages/mongo/.1.1.0.1jqg8g6++os+web.browser+web.cordova/npm/node_modules/mongodb/lib/mongodb/db.js:1758:29
W20150327-13:26:24.932(2)? (STDERR)     at [object Object].Connection.write (/Users/jaro/.meteor/packages/mongo/.1.1.0.1jqg8g6++os+web.browser+web.cordova/npm/node_modules/mongodb/lib/mongodb/connection/connection.js:272:16)
W20150327-13:26:24.932(2)? (STDERR)     at __executeQueryCommand (/Users/jaro/.meteor/packages/mongo/.1.1.0.1jqg8g6++os+web.browser+web.cordova/npm/node_modules/mongodb/lib/mongodb/db.js:1752:16)
W20150327-13:26:24.932(2)? (STDERR)     at Db._executeQueryCommand (/Users/jaro/.meteor/packages/mongo/.1.1.0.1jqg8g6++os+web.browser+web.cordova/npm/node_modules/mongodb/lib/mongodb/db.js:1902:7)
W20150327-13:26:24.933(2)? (STDERR)     at Db.command (/Users/jaro/.meteor/packages/mongo/.1.1.0.1jqg8g6++os+web.browser+web.cordova/npm/node_modules/mongodb/lib/mongodb/db.js:1183:8)
W20150327-13:26:24.933(2)? (STDERR)     at Collection.group (/Users/jaro/.meteor/packages/mongo/.1.1.0.1jqg8g6++os+web.browser+web.cordova/npm/node_modules/mongodb/lib/mongodb/collection/aggregation.js:228:13)
=> Exited with code: 8
like image 371
Jaro Avatar asked Mar 27 '15 07:03

Jaro


Video Answer


1 Answers

As of Meteor v1.0.4:

Provide direct access to the collection and database objects from the npm Mongo driver via new rawCollection and rawDatabase methods on Mongo.Collection

So you can call collection.rawCollection() to get the underlying collection object:

var rawCollection = Orders.rawCollection();

This rawCollection has a method group which is equivalent to the group method in the MongoDB shell. The underlying node API is asynchronous, though, so you'll want to convert it to a synchronous function somehow. We can't use Meteor.wrapAsync directly since group takes function arguments that aren't the primary callback, so we'll work around this with a wrapper:

function ordersGroup(/* arguments */) {
    var args = _.toArray(arguments);
    return Meteor.wrapAsync(function (callback) {
        rawCollection.group.apply(rawCollection, args.concat([callback]));
    })();
}

Inside your method, you can call ordersGroup like you would db.orders.group in the Mongo shell. However, the arguments are passed separately, rather than in an object:

ordersGroup(keys, condition, initial, reduce[, finalize[, command[, options]]])

For more information, see this documentation (although note that the callback parameter should be left out, as our async-wrapping takes care of that).

So you'll have to pass them in separately:

var result = ordersGroup(
    // keys
    function(doc) {
        return { year: doc.createdAt.toISOString().substring(0, 4) };
    },

    // condition
    {createdAt: {$lt: new Date("2015-12-31"), $gt: new Date("2015-01-01")}},

    // initial
    {months: {}},

    // reduce
    function(order, result) {
        var month = order.createdAt.getMonth()+1,
            date = order.createdAt.getDate();

        month = result.months[month] || (result.months[month] = {});
        date = month[date] || (month[date] = []);
        date.push(order);
    }
);

Of course, this only works on the server, so make sure your method is in server-only code (preferably in the server subdirectory, or inside an if (Meteor.isServer)).

like image 139
user3374348 Avatar answered Oct 08 '22 20:10

user3374348