_publishCursor and "update failed: Method not found"

I have some client-side collections, one of them is

ArticleMetadata = new Mongo.Collection('articleMetadata');

I access it through the following publication, which is in the server-part of the code:

Meteor.publish('articleMetadata', function(parameters) {
  if(parameters.articleSpaceId) {
    var cursor = Articles.find({
      owner: this.userId,
      spaceId: parameters.articleSpaceId
    }, {
      fields: { // exclude body field
        body: false
      }
    });
    Mongo.Collection._publishCursor(cursor, this, 'articleMetadata');
    this.ready();
  }
});

(the Articles collection is available to both server and client)

When I use publications of this kind, I get update failed: Method not found errors in the browser console, which are printed by debug.js. Hence I guess my publication using _publishCursor is somewhat related to this error message.

Please give me a hint how to fix these update errors. Actually I do not even perform updates on those publications.

Thank you.
Chris

Why not just return cursor?
But update failed: Method not found looks like when you remove insecure package and try to update the Collection from the client. It tryes to call `/<collection_name>/update``` method on the server

surely he is doing because he wants to send documents to a different collection, and yes this error should be by updates being made outside the publication

I am doing something like this: http://danblog.io/meteor-tips-and-workarounds (please scroll to the section “Client only collections”)

How can I see which part of my code is trying to call the update method? Actually I am just reading my collections, not updating. At least not intentionally…

try using a return in the end of your publication

Meteor.publish('articleMetadata', function(parameters) {
  if(parameters.articleSpaceId) {
    var cursor = Articles.find({
      owner: this.userId,
      spaceId: parameters.articleSpaceId
    }, {
      fields: { // exclude body field
        body: false
      }
    });
    Mongo.Collection._publishCursor(cursor, this, 'articleMetadata');
  }
  return this.ready();
});

and this is your publication with publish relations

Meteor.publishRelations('articleMetadata', function (parameters) {
  if (parameters.articleSpaceId) {
    this.cursor(Articles.find({
      owner: this.userId,
      spaceId: parameters.articleSpaceId
    }, {
      fields: { // exclude body field
        body: false
      }
    }), 'articleMetadata');
  }
  return this.ready();
});

What do you mean by that? Actually I thought I was just reading. I use article metadata just for passive menu items.

Maybe there is some updating behind the scenes?

This is what I do:

$scope.articles = $meteor.collection(function() {
  return ArticleMetadata.find({}, {sort: {shortTitle: 1}});
});

FYI: $meteor stems from Angular-Meteor.
$scope.articles is used to set the HTML texts of hyperlinks. No updates at all.

Actually my current version uses return statements like you suggest. The error is still occurring.

Thank you for pointing me to publishRelations, like that :smiley:

But I still do not understand, why Meteor is trying to update…

if I’m not really doing any operation on the client that might interfere I can recommend you the following

  • Test by sending the documents to a different collection, there may be a conflict with the current collection
Mongo.Collection._publishCursor(cursor, this, 'articles');
  • Test using observeChanges directly in your publication
// Mongo.Collection._publishCursor do this
var observeHandle = cursor.observeChanges({
    added: function (id, fields) {
      sub.added(collection, id, fields);
    },
    changed: function (id, fields) {
      sub.changed(collection, id, fields);
    },
    removed: function (id) {
      sub.removed(collection, id);
    }
  });

sub.onStop(function () {observeHandle.stop();});

I tried it using observeChanges: no success
Even renamed it to 'articleMetadata2'

Articles = new Mongo.Collection('articles');
Articles.allow({
  update: function(userId, doc, fields, modifier) {
    // can only change your own documents
    return doc.owner === userId;
  }
});

if (Meteor.isClient) {
  // this code only runs on the client
  ArticleMetadata = new Mongo.Collection('articleMetadata2');
  // further collections here
}

if (Meteor.isServer) {
  Meteor.publish('articleMetadata2', function(parameters) {
    if(parameters.articleSpaceId) {
      var self = this;
      var handle = Articles.find({ owner: this.userId, spaceId: parameters.articleSpaceId }).observeChanges({
        added: function(id, fields) {
          self.added('articleMetadata2', id, fields);
        },
        changed: function(id, fields) {
          self.changed('articleMetadata2', id, fields);
        },
        removed: function(id) {
          self.removed('articleMetadata2', id);
        }
      });
      self.ready();
      self.onStop(function() {
        handle.stop();
      });
    
    }
  });
}

Then in an AngularJS controller:

$scope.$meteorSubscribe('articleMetadata2', { articleSpaceId: articleSpace._id });

,

$scope.articles = $meteor.collection(function() {
  return ArticleMetadata.find({}, {sort: {shortTitle: 1}});
});

Still no success… I am getting exactly the same error message again.

How can I debug it? I need to know where the error message stems from.

you still see the same error or is it different?

EDIT: your error looks like this?
https://gyazo.com/c94437a36647171c544fca573d96ebe7

still update failed: Method not found

The error message is exactly the same, but there aren’t any update calls in my code, nor reasons for updates, nor reasons for a missing update method.

Maybe I need something like

Articles.allow({
  update: function(userId, doc, fields, modifier) {
    // can only change your own documents
    return doc.owner === userId;
  }
});

For the ArticleMetadata collection?

ArticleMetadata.allow({
  update: function(userId, doc, fields, modifier) {
    // can only change your own documents
    return doc.owner === userId;
  }
});

Does not change anything.

Try using

ArticleMetadata = new Mongo.Collection('articleMetadata', {connection: null});
1 Like

Well and what exactly do you expect it to do?

The physical real collection is Articles.

You are working above ArticleMetadata - so the update/insert/remove etc need to be defined above ArticleMetadata. But as there is no such server-side collection, it cannot be defined => not used.

You can insert/update/remove in Articles, but than use Articles.update instead of ArticleMetadata.update.

Please note that my own code does not use update at all. I currently just use the collection to build a static menu.

Thank you Rob, that does the trick :slight_smile:

At least the error message disappeared, now I will test if there are any side-effects.

1 Like

Side-effect: Nothing retrieved from the server any more …

Too much magic for me …

What is the preferred way to share a single server-side collection among different client-side collections? Because that is what I am trying to achieve actually …

My use case:

My articles (Mongo documents) live on the server. The client shows article metadata (titles/URLs/… in my case) in the menu of articles, but not their huge bodies. AND the client can edit individual articles, body included.

Currently, I have one client-side collection for the menu (which excludes the body field) and one client-side collection for editing the article.

I am using low level publish API for some data retrieval, transformation/aggregating between few collection and than pushing to client.
But for our usecase non-reactive was enough.

Still in Meteor.publish documentation that room count example is how to do some basic reactive custom publish.

Well I am already using that low-level kind of publish in order to provide JSON versions of my articles. But I do not see how it could solve that error message problem.

In fact I am pretty astonished that no one else faced my use case/problem in the past, since it seems nothing special to me, more like an everyday use case.

I regard the un-documented _publishCursor as a handy shortcut for observeChanges if I do not need custom added, changed and removed handlers. After all replacing _publishCursor by observeChanges gives me the same result, plus a bunch of additional lines of code…

Meteor.publish('jsonArticles', function(parameters) {
  if(parameters.articleSpaceId) {
    var self = this;
    var handle = Articles.find({ owner: this.userId, spaceId: parameters.articleSpaceId }).observeChanges({
      added: function(id, fields) {
        self.added('jsonArticles', id, {
            spaceId: fields.spaceId,
            urlId: fields.urlId,
            json: JSON.stringify(fields, null, 2)
        });
      },
      changed: function(id, fields) {
        self.changed('jsonArticles', id, {
            spaceId: fields.spaceId,
            urlId: fields.urlId,
            json: JSON.stringify(fields, null, 2)
        });
      },
      removed: function(id) {
        self.removed('jsonArticles', id);
      }
    });
    self.ready();
    self.onStop(function() {
      handle.stop();
    });
  }
});