How to query a document mongodb and react

Hi guys, I wonder why this is not working…

This function should return true if there are any documents that match query.

Thing I want to do is if the frequency is one time, just want to set query with creatorDetails.uuid and measureId to find()

  hasCompleted(userId) {
     // ....
    const query = {
      'creatorDetails.uuid': userId,
      measureId: this._id,
    };

    if (this.typeOptions.frequency === Frequency.ONE_TIME) {
      return query;
    }
    // ....
    console.log(query);
    return MeasureData.find(query).count() > 0;
}

query console.log

{
  creatorDetails.uuid: "wD7BaeY6SsNSBgjbg"
  measureId: "GFKdwrmwkZ6FkAsco"
}

Now I’m looking at studio 3t and there is a document matching this

db.getCollection("MeasureData").find({
    "creatorDetails.uuid" : "wD7BaeY6SsNSBgjbg", 
        "measureId": "GFKdwrmwkZ6FkAsco",
})

but this hasCompleted() still returns false…

Are you calling this function on the client or on the server? If on the client: have you published and subscribed to the data (check the meteor-dev tools in your browser? Can you find the data you expect in Minimongo?)

Thank you for your answer!

hasCompleted() is on the server side and the client side call hasCompleted with useTracker.

  const hasCompleted = useTracker(
    () => survey.hasCompleted(Meteor.myFunctions.getCurrentUserId()), // this
    [JSON.stringify(survey)],
  );

This survey.hasCompleted() looks like this in server side

  hasCompleted(userId) {
    const questionIds = this.questions.map(question => question._id);
    const measures = Measures.find({questionId: {$in: questionIds}});

    switch (this.frequency) {
      case Frequency.ONE_TIME:  {
        return measures.fetch().every(measure => {
          measure.hasCompleted(userId); // this
        });
      }
    }
  },

And measure.hasCompleted(userId); will be also inside server side.

  hasCompleted(userId) {
     // ....
    const query = {
      'creatorDetails.uuid': userId,
      measureId: this._id,
    };

    if (this.typeOptions.frequency === Frequency.ONE_TIME) {
      return query;
    }
    // ....
    console.log(query);
    return MeasureData.find(query).count() > 0;
}

When you call survey.hasCompleted on the server that should probably work. But when you call that same function on the client it will not get any data from Measures.find unless you published the data on the server and then subscribe to it on the client. Collections work differently on the client and on the server. On the server Measures.find will go to the MongoDB driver and execute db.getCollection("MeasureData").find. But we don’t have direct access to MongoDB on the client but instead we have something called Minimongo that behaves a lot like MongoDB and contains a copy of some of the data of the MongoDB - if that data has been published on the server and if you have subscribed to that publication. And my guess is, that you did not publish and subscribe.

But at least in the code you have shown here you pretty much only use the count of the cursor. So unless you need all the data (and reactively) you should not use pub/sub like this. You don’t want to synchronise all the data sets just to count them. Then you should use either a custom publication or probably even better use Meteor methods.

You should probably review Publications and Data Loading | Meteor Guide and Methods | Meteor Guide and then create a fresh Collection with Publications and Methods and a React Component to grab some data and keep it really, really simple. Data fetching in Meteor isn’t hard, but it’s different from Rest apis and when you are new to it you get confused quite easily. Most of us have been there. So take a little time to go back to very easy examples and when you get those down you will figure out the stuff you are working on. And get the Meteor dev tools for chrome. Especially Publications are much easier to grasp when can see what happens in Minimongo.

1 Like

Like you suggest, I think using meteor methods sounds a good option for this case.

and yes I’m new to meteor so still not really understanding pub/sub, method, minimongo and all other stuff…

I will take a look the document you linked.

Thank you very much!

Blockquote I think using meteor methods sounds a good option for this case.

If you need only know the measurement status on client side, the method will be great for that. If you will need to have also the measurements data, publications will be probably better solutions.

1 Like

I use a publication, subscribe to it and use tracker to attach to a prop in the react component

2 Likes

@nodsec @truedon @janmp

Thank you for you all answers!

But now I found both hasComplated function is inside helpers.

Measures.helpers({
// ...
  hasCompleted(userId) {
     // ....
    const query = {
      'creatorDetails.uuid': userId,
      measureId: this._id,
    };

    if (this.typeOptions.frequency === Frequency.ONE_TIME) {
      return query;
    }
    // ....
    console.log(query);
    return MeasureData.find(query).count() > 0;
}
// ...
})

Wouldn’t helpers act like meteor.methods?

We can use the dburles:collection-helpers package to easily attach such methods (or “helpers”) to documents.

Bro what is this you just use subscriber and props you kinda trying to reinvent the wheel

You could then call Measures.hasCompled(someUserId) instead of Measures.find({'creatorDetails.uuid': someUserId, [...]}).count()

But on the client that will still yield 0 unless you take care of pub/sub yourself.
It just adds some methods to the wrappers that Meteor builds around MongoDB- and Minimongo- Collections.

1 Like

@janmp

Nice Thank you!

There’s really no way past dealing with pub/sub or methods (unless you want to go with the autopublish and insecure packages, wich just take care of pub/sub for you by publishing everything to everyone, wich ist probably not what you want in most cases - totally fine for quick little apps you just want to run locally for just yourself, though).

1 Like