Reputation: 478
I understand that the 'mini-mongo' packaged with meteor up till 0.6 had a few limitations around aggregation, but hoping the story is a bit easier with the release of 0.6.
What I'm trying to work around is the lack of 'aggregation' in mini-mongo.
I have a mongodb with records like this
db.account_records.findOne()
{
"type" : "initial_balance",
"amt" : 10,
"account_id" : "95CPB9Be8NX3TGSpi",
"_id" : "L9D7Agt4gW2Ht4NTA"
}
and I want to subscribe (at client) to a query like the following..
db.events.aggregate( [ { $group: {_id:"$account_id", balance: { $sum: "$amt"}}}]);
.. which gives (when run using "real" mongodb from terminal "mongo meteor" style)..
{
"result" : [
{
"_id" : "Dn5Eouw8K4RrP9SGw",
"balance" : 169.99922000000308
},
{
"_id" : "Bawopno2QGs8guMWy",
"balance" : 1
},
{
"_id" : "95CPB9Be8NX3TGSpi",
"balance" : 5
}
],
"ok" : 1
}
It seems unlikely to me that it will ever be possible (or desirable) to perform complex aggregate clauses client side so i can see the reason we have mini-mongo. But I was hoping that with the ability to install standard npm modules in the new version of meteor it might be a bit easier to create a query that I can publish from 'real' mongo and subscribe to in mini-mongo?
--
PS I found this already but all those double underscores are making me nervous I'd be attempting something complicated... https://github.com/meteor/meteor/pull/644
Upvotes: 3
Views: 1033
Reputation: 2940
to fix Akshat's answer for Meteor 0.9.0, use this:
self.find()._mongo._withDb(function(db) {
return db.createCollection(self._name, function(err, collection) {
if (err) {
console.log(err);
future.throw(err);
return;
}
return collection.aggregate(pipeline, function(err, result) {
if (err) {
future.throw(err);
return;
}
return future["return"]([true, result]);
});
});
});
Also, no need to include MongoDB = Npm.require("mongodb")
in the header.
Upvotes: 1
Reputation: 75945
You can use that aggregation push on your server as used. Prior to the Meteor 0.6.0 'engine' version npm
module integration was still very unofficial hence the underscores, finally it can be used officially so below should work (from that github pull modified to work on 0.6.0 : https://github.com/meteor/meteor/pull/644)
Server side js
var path = Npm.require('path');
var MongoDB = Npm.require('mongodb');
var Future = Npm.require('fibers/future');
var Animals = new Meteor.Collection("animals");
Meteor.startup(function () {
Animals.aggregate = function(pipeline) {
var self = this;
var future = new Future;
self.find()._mongo.db.createCollection(self._name, function (err, collection) {
if (err) {
future.throw(err);
return;
}
collection.aggregate(pipeline, function(err, result) {
if (err) {
future.throw(err);
return;
}
future.ret([true, result]);
});
});
var result = future.wait();
if (!result[0])
throw result[1];
return result[1];
};
});
Meteor.methods({
myAggregationMethod: function() {
return Animals.aggregate([ {$project: {dog:1, age:1}}, {$sort:{age:1}} ]);
}
});
And on your client js, when you want to call an aggregation:
Meteor.call('myAggregationMethod', function(err,result) {
if (!err) {
console.log(result)
} else {
console.log(err);
}
});
Adding the mongodb package
1) Make a directory in your project called packages to store your packages & in that another directory called mongodb for the mongodb npm package
2) Add a file in mongodb called package.js
containing
Package.describe({
summary: "Mongodb driver"
});
Npm.depends({'mongodb':"1.2.14"});
Package.on_use(function (api) {
api.add_files('lib.js', 'server');
});
Add another file in the same mongodb directory called lib.js
containing:
if(typeof(Npm) != "undefined") {
MongoDB = Npm.require("mongodb");
}
else
{
console.log("Please upgrade meteor to 0.6.0")
MongoDB = __meteor_bootstrap__.require("mongodb");
}
Finally remove the line
var MongoDB = Npm.require("mongodb")
from your server.js
as we globally scoped it in lib.js
Upvotes: 2