How to make a mongo group on the server side of Meteor

In the meteor mongo shell, I can use db.collection.group, but from Meteor.methods I can, because Meteor does not support it.

How could I write a method that 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")}}]} }) 

The expected result is an array of groups of objects by month, and then grouped by dates within the months.

PS orders , this is a pretty large collection, and I really want to do grouping in the database.


After getting the rawCollection () information 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 get:

 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 
+5
source share
1 answer

According to Meteor v1.0.4:

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

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

 var rawCollection = Orders.rawCollection(); 

This rawCollection has a group method that is equivalent to the group method in the MongoDB shell. The underlying API node is asynchronous, so you want to somehow convert it to a synchronous function. We cannot use Meteor.wrapAsync directly, since group accepts function arguments that are not the main callback, so we will deal with the shell:

 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, db.orders.group in the Mongo shell. However, the arguments are passed separately, and not in the object:

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

See this documentation for more information (although note that the callback parameter should be omitted since our processing of async packets is from this).

So, you have to pass them 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 the server-only code (preferably in the server subdirectory or inside if (Meteor.isServer) ).

+5
source

Source: https://habr.com/ru/post/1216253/


All Articles