Running specific code on client only when data from server is updated

Hi all!
I’m fetching some data on server side in 5 minutes interval. The data is then consumed by client and displayed on a page using React. I’m using a simple useTracker() hook for that purpose, e.g.:

const Events = () => {
  const events = useTracker(() => EventsCollection.find({}).fetch());

  return (
    <ul>
      {events.map(e => 
        <li>{e.timestamp}: {e.name} {e.amount}</li>
      )}
    </ul>
  )
}

All this works fine so far, however, I’d like to send a browser notification to user only if a specific condition is met when data from server gets updated. This is a bit problematic since my component doesn’t receive new data only when new data on server side is fetched, ultimately resulting in browser notifications being triggered more than once every 5 minutes (understandably, I’m receiving the same set of data all the time).

What I’m trying to achieve is something like this:

const AppContextProvider = props => {
  const [state, dispatch, updatedState] = useAppState();

  useTracker(() => {
    Events.find({}).fetch().map(e => {
      if (updatedState.current.userSettings.amount === e.amount) {
        // Trigger this notification only once, when server actually
        // updates the data in MongoDB and if the condition above is met.
        new Notification('Title', { body: `${e.name}: ${e.amount}` });
      }
    });
  });

  return (
    <AppContext.Provider value={{ state, actions }}>
        {props.children}
    </AppContext.Provider>
  )
}

Is something like this possible or can someone suggest some other approach to achieve this? Thanks in advance!

You can use Meteor Publications/Subscriptions with poll and diff: Tuning Meteor Mongo Livedata for Scalability | by Meteor Software | Meteor Blog

Thanks for the reply!
I ended up creating an interval on client side and removing useTracker() hook, similar to this:

const AppContextProvider = props => {
  const [state, dispatch, updatedState] = useAppState();

  const checkEvents = () => {
    Events.find({}).fetch().map(e => {
      if (updatedState.current.userSettings.amount === e.amount) {
        new Notification('Title', { body: `${e.name}: ${e.amount}` });
      }
    });
  }

  useEffect(() => {
    setInterval(checkEvents, 5 * 60 * 1000);
  }, []);

  return (
    <AppContext.Provider value={{ state, actions }}>
        {props.children}
    </AppContext.Provider>
  )
}

This seems fine to me, but I just wonder if this approach is ok in general, or are there some potential consequences which I’m maybe not experiencing at the moment?

@_errata For this case you can use observe or observeChanges to know when the cursor has new results, and then deliver your notification to the user.

One thing I did for an app of mine here was something along these lines here (in Blaze):

Counts.find({ _id:  "userNotificationCount" }).observe({
            changed({ count: newCount }, { count: oldCount }) {
              if (newCount === oldCount || oldCount > newCount) {
                return;
              }

              const limit = newCount && oldCount && newCount - oldCount;
              if (!limit) return;
              Meteor.call(
                'getNotificationsForUser',
                { limit, ...args },
                (err, result) => {
                  if (err) {
                    console.warn(err);
                    return;
                  }

                  triggerNotification("Notification Text");
                }
              );
            },
          });

Basically you observe the cursor from your subscription (client side) and react to changes added there. In my case, as I was already publishing the notification count for the user, I would only fetch new notifications when this count increased.

Getting back to your original post “I’m fetching some data on server side in 5 minutes interval.”
It may be the case that you fetch from a 3rd party. In this case you can do 2 things:

  1. Save it to MongoDB and publish it to the client.
  2. I think the most scalable solution in this case, to avoid observers (publications), is to “announce” connected users of this updated data via Node Events. Have clients subscribed to a topic and upon successful fetch of data, notify all users of this new data. Users can fetch it via the Event emission if content is rather small of pull from Mongo via a Method.