matteodem / meteor-easy-search

Easy-to-use search for Meteor with Blaze Components
MIT License
435 stars 68 forks source link

After upgrade to METEOR@2.3.5 new Index fails with "Match error: Expected particular constructor" when using Meteor.users #659

Closed lauff closed 3 years ago

lauff commented 3 years ago

After upgrading to METEOR@2.3.5 the following

import { Meteor } from 'meteor/meteor';
import { Index, MongoDBEngine } from 'meteor/easy:search';

export const ContactsIndex = new Index({
  collection: Meteor.users,
  fields: [...],
  engine: new MongoDBEngine({...})
});

fails with "Match error: Expected particular constructor" on the line with "new Index()"

After replacing the Metor.users collection with a dummy collection it works without an error message:

import { Meteor } from 'meteor/meteor';
import { Index, MongoDBEngine } from 'meteor/easy:search';

const DummyCollection = new Mongo.Collection('DummyCollection');

export const ContactsIndex = new Index({
  collection: DummyCollection,
  fields: [...],
  engine: new MongoDBEngine({...})
});

Remark: I replaced some code by '...' as this did not seem to cause the issue.

matteodem commented 3 years ago

Is it possible to show the full code?

lauff commented 3 years ago

Thanks for your help, here is the full code.

import { Meteor } from 'meteor/meteor';
import { Index, MongoDBEngine } from 'meteor/easy:search';

// On Client and Server
export const ContactsIndex = new Index({
  collection: Meteor.users,
  fields: ['personal02.firstName','personal02.lastName','phonesARRAY','emailsARRAY'],
  engine: new MongoDBEngine({

    selectorPerField: function (field, searchString) {

      function escapeRegExp(string){
        return string.replace(/[.*+?^${}()|[@\]\\]/g, '\\$&'); // $& means the whole matched string
      }

      if (['personal02.firstName','personal02.lastName'].includes(field)) {
        let pos = searchString.indexOf(' ');
        if (pos !== -1) {
          if ('personal02.firstName' === field) {
            return {  
              $and: [
                { 'personal02.firstName': { '$regex' : '^' + escapeRegExp(searchString.substring(0,pos)) + '.*', '$options' : 'i' }},
                { 'personal02.lastName': { '$regex' : '^' + escapeRegExp(searchString.substring(pos+1)) + '.*', '$options' : 'i' }}
              ]
            };
          }
          if ('personal02.lastName' === field) return;
        }
      }

      if ('emailsARRAY' === field) {
        //console.log('escapeRegExp()',searchString,escapeRegExp(searchString));
        return { 'emails': { $elemMatch: { address: { '$regex' : '.*' + escapeRegExp(searchString) + '.*', '$options' : 'i' }}}};
      }

      if ('phonesARRAY' === field) {
        // return this selector if the phones field is being searched
        return { 'address.phones': { $elemMatch: { phone: { '$regex' : '.*' + escapeRegExp(searchString) + '.*', '$options' : 'i' }}}};
      }

      // use the default otherwise
      return this.defaultConfiguration().selectorPerField(field, searchString);
    },

    beforePublish: function (action, doc) {
      // might be that the field is already published and it's being modified

      doc.displayNameString = doc.displayName();

      let age = doc.age();

      if (age === null) doc.ageString = '';
      else if (age === 0) doc.ageString = '(0 Jahre)';
      else if (age === 1) doc.ageString = '(1 Jahr)';
      else doc.ageString = `(${age} Jahre)`;

      return doc;
    },

    fields: function (searchObject, options) {
        //console.log('DEBUG 3', searchObject, options);
        return {'___NotAvailable___' : 1, 'personal03.birthday': 1}; // dummy to return nothing (besides the calculated displayNameString)
    },
  }),
});
matteodem commented 3 years ago

I'll have a look at this next week

lauff commented 3 years ago

Have you already been able to look into this?

Thanks for your help, Markus

lauff commented 3 years ago

I looked into the latest code (unreleased version 2.2.3) and found an undocumented config option ignoreCollectionCheck for the Index config object. Setting this to true resolved the problem.