Update collection without publishing change


#1

I have a collection. I need to update a property on that collection. Sed update may change a second property on the collection. I don’t need to send the first property to the client so I have {fields: {prop1: 0}} set on Collection.find on the server.

I only what the change to be sent to the client if the second property changes. My issue is that the collection is republished even when only the first property is changed (the one that isn’t sent to the client).

Is there solution to this? My current workaround is to put the first property in a second collection.

Cheers
Chris


#2

There is a way to know which fields change using observeChanges

Although I am unsure if you can stop sending the changes to the subscribed clients

What I am sure is that RedisOplog can do what you wanted to do because the reactivity is controlled by your app:


#3

This should not be an issue. If property1 is not published, then changes to that property1 will not send any data to the subscribed clients.

Unless that field is subscribed by the client via a different publication of the same collection. Have you checked this scenario?


#4

Thanks for the suggestion. Unfortunately, I’ve set it to 0 on all publications and it’s the same. I’ve even created a simple standalone test and I have the same issue. Below is my collection code. As you can see, lastAccessed is Property 1 and index is Property 2. If the index is already set to 0, then nothing should change, but the component is still being re-rendered.

Upon further inspection, I see that two re-renders are being called. The first has the lastAccessed property on only the one item that was updated. The second render has removed the lastAccessed property altogether. This doesn’t look like expected behaviour.

Did I explain myself well enough? I can push the project if it helps.

Cheers
Chris

import { Mongo } from "meteor/mongo";
import { Meteor } from "meteor/meteor";

export const Items = new Mongo.Collection("items");

if (Meteor.isServer) {
  Meteor.publish("items", function itemsPublication() {
    return Items.find(
      {},
      {
        fields: {
          lastAccessed: 0
        }
      }
    );
  });
}

Meteor.methods({
  updateLastAccessed(id) {
    Items.update({ _id: id }, { $set: { lastAccessed: new Date() } });
    let item = Items.findOne({ _id: id });
    if (item.index !== 0) {
      let items = Items.find({}, { sort: { lastAccessed: -1 } }).fetch();
      items.map((e, i) => {
        Items.update({ _id: e._id }, { $set: { index: i } });
      });
    }
  },
  insert(name) {
    Items.insert({name: name, lastAccessed: new Date(), index: -1 });
  }
});

#5

ok… have you removed the autopublish package?


#6

Yup.
> meteor remove autopublish

autopublish is not a direct dependency in this project.


#7

Ahh, I think I have resolved it. The fields need to be specified on the client, not the server. This way it is no longer updating when lastAccessed changes.

What’s even nicer here is that I don’t need to return index. I can sort on index and only need to return name.

let TrackedApp = withTracker(props => {
  handle = Meteor.subscribe("items");

  return {
    ready: handle.ready(),
    items: Items.find({}, { sort: { index: 1 }, fields: {name: 1} }).fetch()
  };
})(App);

#8

Is there any way of telling whether the data still makes it to the client or not? My concern is minimising network load.


#9

use something like https://chrome.google.com/webstore/detail/meteor-devtools/ippapidnnboiophakmmhkdlchoccbgje


#10

In client, you are querying from minimongo. So even if you filter in the client, it is still possible that the publication is sending the data to minimongo. I’m not sure if that is the solution to minimize network load.


#11

Thanks to you both for your replies - with your help and that of the chrome extension, I’ve managed to get a better understanding of how the publications work and and get to the bottom of my issue. I’ll explain for those that Google their way onto this page in the future.

The issue occurs because the Meteor method call is running on both the client and the server. So whilst the server is not publishing Property 1 (lastAccessed), both the server and client are updating the lastAccessed field. That puts it into the client collection, then takes it away again once Mongo and MiniMongo sync.

One solution is to do the processing inside the method call on the server side only. But that can create unnecessary latency. Instead, I publish both fields from the server (so they both end up in minimongo), but hide the field from the client-side query. This allows the client to make the update (without waiting for confirmation from the server), and also means that the components are not re-rendered if only Prop 1 is updated.