Don't render until database change is complete


#1

Hi all,

I have a Python script that sends 3000 rows to a Meteor MongoDB collection, and after a few minutes, deletes all the documents inside the collection, and then re-uploads 3000 documents. This process repeats every few minutes.

On my UI, I have a table displaying all 3000 documents and a text box showing the count of documents (i.e. “3000”). The UI isn’t fast enough to render this when the Python script executes and makes changes to the database. Because of this, the text box goes from 0 to 260 to 500 to 1600 to 3000 (since it takes some time to load up 3000 rows in the table). Is there a way I can either:

  1. Prevent the text box from showing intermediate database changes, i.e. it should go from 0 straight to 3000.
  2. Prevent the UI from rendering at all until all 3000 rows/documents are deleted and re-uploaded.

I read something about ready() but don’t know how to implement that. Thanks.


#2

Use Tracker.Autorun(). As you might have read, .ready() will return true after all the documents are loaded in miniMongo. So you can show the count or docs list after it returns true.

const handle = Meteor.subscribe('docs.list');
Tracker.autorun(() => {
  const isReady = handle.ready();
  if (isReady) {
    let docs = Collection.docs.find();
   // pass data (docs) to ui after subscription is ready

   }
});

#3

Hi @harikrishna9, thanks for your reply. I’m trying to test this out on the React Meteor tutorial, and amended this code in imports\ui\App.jsx:

export default createContainer(() => {
Meteor.subscribe(‘tasks’);

return {
tasks: Tasks.find({}, { sort: { createdAt: -1 } }).fetch(),
incompleteCount: Tasks.find({ checked: { $ne: true } }).count(),
currentUser: Meteor.user(),
};
}, App);

To

export default createContainer(() => {
const handle = Meteor.subscribe(‘tasks’);
Tracker.autorun(() => {
const isReady = handle.ready();
if (isReady) {
return {
tasks: Tasks.find({},{ sort: { createdAt: -1} }).fetch(),
incompleteCount: Tasks.find({ checked: { $ne: true } }).count(),
currentUser: Meteor.user(),
}
}
});
}, App);

However this just removed all data from the UI. What am I missing here? Thanks.


#4

createContainer() handles Tracker.autorun() for you!
so this should work as expected:

export default createContainer(() => {
  const handle = Meteor.subscribe('tasks');
  const isReady = handle.ready();
  
  if (isReady) {
    return {
      tasks: Tasks.find({},{ sort: { createdAt: -1} }).fetch(),
      incompleteCount: Tasks.find({ checked: { $ne: true } }).count(),
      currentUser: Meteor.user(),
    };
  }
}, App);

#5

It still seems to stop loading up anything in the UI. If I try:

if (!isReady)

It loads everything back up again. So my documents are never done loading?

Edit: I also have autopublish and insecure packages removed.


#6

I got this to work using

Meteor.subscribe('getlogins');
Template.loginstemplate.helpers({
	'ready': function () {
		return Template.instance().subscriptionsReady();
	},

It does wait for the subscription to to be ready, however, the counter doesn’t go from 0 to 3000 instantly, since it’s the rendering that takes time. Is there any “don’t show changes until render complete” kind of function in Meteor? @harikrishna9 @Chris.R