Search code examples
meteorminimongo

Exception in template helper: Error: Match error


I'm trying to perform a custom sort using a comparator function from within a template helper in Meteor.

Here is my template helper:

Template.move_list.helpers({
  assets() {
    return Assets.find({}, { sort: sortFunction });
  }
});

And here is the comparator function:

const sortFunction = function (doc1, doc2) {
  const barcodes = Session.get('barcodesArray');

  if (barcodes.indexOf(doc1.barcode) === -1 || barcodes.indexOf(doc2.barcode) === -1) {
    return 0;
  }

  let last = null;
  _.each(barcodes, function (barcode) {
    if (barcode === doc1.barcode) last = doc1.barcode;
    if (barcode === doc2.barcode) last = doc2.barcode;
  });

  return last === doc1.barcode ? 1 : -1;
}

Error

When the page loads, the following error is returned:

Exception in template helper: Error: Match error: Failed Match.OneOf, Match.Maybe or Match.Optional validation

I put a breakpoint in chrome into the sortFunction, however the function was never entered and the breakpoint never reached.

Of course, the error is not throw when I remove sort.

References

This feature is not very well documented, however here is the relevant part of the docs:

For local collections you can pass a comparator function which receives two document objects, and returns -1 if the first document comes first in order, 1 if the second document comes first, or 0 if neither document comes before the other. This is a Minimongo extension to MongoDB.

And the commit by mitar adding the functionality, with example code from the test:

var sortFunction = function (doc1, doc2) {
  return doc2.a - doc1.a;
};

c.find({}, {sort: sortFunction})

Can anyone make sense of this error?


Solution

  • Edit:

    This issue should be resolved in Meteor >= v1.3.3.1.

    Local collections (i.e, client-side and in-memory server-side collections) will allow to pass a function as the sort clause.


    The error comes from the mongo package, where the spec does not allow sort to be a function.

    @mitar changed LocalCollection in the minimongo package. LocalCollection is part of the Mongo.Collection object on the client (its _collection attribute), but queries are still checked according to the original mongo spec. I believe this to be a bug, as the spec was not updated to reflect the change.

    To overcome this (in the meantime), either have the function accept a sub-field, such that the sort value is an object:

    var sortFunction = function (x, y) {
      return x - y;
    };
    c.find({}, {sort: {a: sortFunction}});
    

    or use the c._collection.find() instead, which will work (as far as I can tell), except it will not apply any transformations defined for the collection.

    var sortFunction = function (doc1, doc2) {
      return doc2.a - doc1.a;
    };
    c._collection.find({}, {sort: sortFunction});