utunga
utunga

Reputation: 478

is it possible to package a 'real' mongodb library for use on the *server* side only in meteor 0.6

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

Answers (2)

maxko87
maxko87

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

Tarang
Tarang

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

Related Questions