Get data from publication or/and from a call method

Hi,
I am confronted with a small problem …

I make an application that contains products …

On a page, I want to display my products by 20 with a paging system. I got my data from a publication I subscribe to … with option to define the number of elements to skip according to the page number and got only specifics fields…

So far, so good.

Now I have to retrieve the total number of products from this same page to display a counter like: Page 1 (20 products on 50000).

of course, I do not want to load the entire collection just to know the number of items in my collection …

So, I tried to make a second publication to only count the number of elements in the collection, but it is apparently not the right way to do, since I have no way to access this value since the Variable of my collection.
I currently have not found a way to assign the content of a publication using the same collection than another to a different variable name than the one of the collection … Moreover, a publication seem to be supposed to return only a array or object . But here I need only a simple number. The publication does not seem to be the right method to use to obtain this value.

So… I was going to recover this value with a “call” method.

It works, I get my value, but I can not use it in a helper probably because the request is asynchronous.

At first I tried to run the method on the onCreated event of my template and assign it to my template Template.myTemplate.productsCount = …

Then return this value from my helper … But it does not work.

I also tried to make the call from the Tracker.autorun function from the helper … But without more success. I can not return the value recover by calling the method, however I can display it with a console.log …

    gotProductsCount(){
        Tracker.autorun((computation) => {
            Meteor.call("productsCountInACategory", this.id, function (err, value) {
                if (err) {

                 alert('error')
                }
                console.log(value); // Yes it show my value in my console... 
                return value

            });
        });


    }

I try also…

    gotProductsCount(){



        function Return(val){
            console.log(val); // Yes it show the val in my console... 
            return val
        }


        Tracker.autorun((computation) => {
            Meteor.call("productsCountInACategory", this.id, function (err, value) {
                if (err) {

                 alert('error')
                }
                console.log(value);
                Return(value)

            });
        });


    }

So, my question is which will be the best way to got different data from the same Collection, from the same page, but without load the entire data ?

And how to use a async methods inside a helper ?

Thank’s for your help,

Mickael

You can combine a subscription and a method call to combine data but the subscription is going to be reactive, updating with changes to the dataset, whereas the method call result is not going to update, which might be a problem if the total count of the collection changes often, in which case you can poll the method.

In fact, there’s an old but still relevant article explaining this:

You can alternatively use any one of

which are dedicated packages that solve this exact usecase.

3 Likes

The problem in your examples is that you can’t return data from a callback. I recommend reading up on callbacks in javascript and why they work the way they do

The easiest solution is to use a ReactiveVar like so:

import { Meteor } from "meteor/meteor";
import { Template } from "meteor/templating";
import { ReactiveVar } from "meteor/reactive-var";

Template.productsList.onCreated(function() {
  this.productsCount = new ReactiveVar();
  
  Meteor.call("productsCountInACategory", this.data.id, (err, value) => {
    if (err) {
      alert("error");
    }
    this.productsCount.set(value);
  });
});

Template.productsList.helpers({
    productsCount() { return Template.instance().productsCount.get(); },
});

Using a ReactiveVar, the helper will re-run whenever the value changes (ie. you called .set ).

In this example the count is only grabbed once, when the Template is about to be rendered. Because Meteor.call is not a reactive data source, it won’t trigger an autorun to re-run, so you’ll need to do it yourself (on page change or on an interval, or you could choose not to care about count updates)

EDIT: I switched the callback to an arrow function because we’re using this in the callback and you want to make sure the correct this is available

4 Likes

Thank you serkandurusoy and coagmano for your answers ! I understand better now… !
I will use the ReactiveVar solution suggested by coagmano, which seems to me more “native” as not dependent on anything other package than ReactiveVar … and it will be a good opportunity to start to learn more about ReactiveVar for me :slight_smile:

Thank’s again

@imike57 remember that it will not update the results reactively if the count of the collection changes!

Therefore that’s not an alternative solution, it is a complementary solution of bringing the method result into the template, in the way that it shows how to wire the async result of the method call to the template’s helper reactively. But for any successive update, you’ll need to follow the steps from the original article.

And the packages (especially the second one) are prepackaged solutions to that problem of getting successive updates to your database, after the first one.

1 Like

Yes, to get it reactive, I guess I have to use https://atmospherejs.com/tmeasday/publish-counts
But from what I read, the performance is not really good for big data collection…

So in my case, refresh the count when I need is enough…

Maybe another reactive solution will be to store the count in a dedicated Count collection and update it after each insert/remove… the performance could be better.

But what I hope for the future that Meteor let us to assign a publication results to a new variable instead to be related to a collection name… Because it looks like a limitation… I think it could simplify some uses, where got data reactivly from different cursor will be required, for example to get from a products collection the products of the current category and show a Top 10 products or other in the same time…

@imike57 these are all available today

Assigning publication results to alternative client side collections is also already possible today:

2 Likes

Thank’s @serkandurusoy
very helpful