Compiling average from aggregate from database and utilizing result within the client


#1

Hey everyone-

Very new to Meteor here, but I am loving it thus far!

I do feel like I’m spinning in circles about something you might be able to help me with.

I am attempting to compile the average “rating” of a “review” object located within an “application” object. I’ll need to publish the result into a local variable that can be used within a template that I show all the application details.

From what I am reading this can be accomplished by publishing on the server, and subscribing to the results on the client. I hope this is correct, so far.

This is where I am running into trouble. I need to $unwind the review objects before I can access them, and I am able to access all the data (and results) from the console, but that’s where it ends. I can’t seem to access any of the data within the framework.

Ideally, I’d like to be able to push the “averageRating” result back into the application object itself, but at least having access to the result on the client side would be sufficient, so it can be displayed at run-time.

Here is what I have so far:
//server code

    Apps = new Mongo.Collection('apps');
    ApplicationSchema = new SimpleSchema({
                name: {
                        type: String,
                        label: 'Name'
                },
                desc: {
                        type: String,
                        label: 'Description'
                },
                numberOfReviews: {
                        type: Number,
                        optional: true,
                        autoform: {
                        type: 'hidden'
                        }
                },
                averageUserRating: {
                        type: Number,
                        optional: true,
                        autoform: {
                        type: 'hidden'
                }
                },
                reviews: {
                        type: [Review],
                        optional: true
                }
});
// this is using the ReactiveAggregate plug-in.

Meteor.publish("reviewAverage", function() {
    ReactiveAggregate(this, Apps, [{
        $unwind: "$reviews",
        $group: {
            '_id': "$_id",
            reviews: { push: '$reviews'}, 
            averageUserRating: { $avg: '$reviews.rating' }
        },
        $project: {
             _id: 0,
             _id: "$_id",
             reviews: 1,
             averageUserRating: 1
        }}], { averageUserRating: "reviewAverages" });

// client code

Template.AppSingle.onCreated(function() {
    var self = this;
    self.autorun(function() {
        self.subscribe('apps'); 
        self.subscribe('reviewAverages');     
});

Template.AppSingle.helpers({
    reviewAverage: () => {
        console.log("Testing subscription!");
        return reviewAverages.find();
    }
});

I can’t seem to get the subscription to the method to work, let alone return the averages I’m looking for.

Perhaps I am way off on this, but can anyone please help point me in the right direction?

Thanks!


#2

Here you’re setting up a publication with a name of reviewAverage (singular).

Here you’re attempting to subscribe to a publication with a name of reviewAverages (plural). These should match.


#3

Thanks. I did fix this, but unfortunately the sub is still not firing. I wonder if my aggregate function isn’t working at all.


#4

Quite possibly - maybe start debugging there. Try reducing/simplifying your aggregation pipeline to see if you can get back any results with something really basic. If you aren’t seeing anything then the problem lies elsewhere. One thing that might also help is checking out a copy of the jcbernack:reactive-aggregate package, storing it within your projects /packages directory, then adding some debugging within the package itself. This way you can trace through exactly what’s happening within the package (which is quite small actually - 56 lines of code).