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
As of Meteor v1.0.4:
Provide direct access to the collection and database objects from the npm Mongo driver via new
rawCollectionandrawDatabasemethods onMongo.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)).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With