2
votes

This is a very specialized case, but quite relevant to anyone wanting to leverage MongoDB's RegExp powered lookups from client (Mini-Mongo) to server (MongoDB) using publications and subscriptions in Meteor. I would like to understand why the disparity between server and client MongoDB query functionality, and develop a pull-request to Meteor if it is A) needed and B) beneficial to other developers.

I. General Case:

  1. Run a Meteor installation with aldeed:meteor-simple-schema, aldeed:collection2, accounts-password, and ejson at a minimum.
  2. Extend EJSON by adding the RegExp type using EJSON.addType with these instructions: How to extend EJSON to serialize RegEx for Meteor Client-Server interactions?
  3. Add a Meteor.user with the email address "[email protected]"
  4. Run this on the Meteor server code (UNEXPECTED RESULT):

    # anywhere on the server
    if Meteor.isServer
      user_selector = { 'emails': { '$elemMatch': { 'address': /^adm/ } } }
      user_count = Meteor.users.find(user_selector).count()
      console.log user_count 
      # prints 0 WHY!?
    
  5. Run this on the MongoDB shell (bypassing Meteor.users):

    # mongo shell
    > db.users.find({ 'emails': { '$elemMatch': { 'address': /^adm/ } } }).count()
    # prints 1
    
  6. Attempt an independent Mongo.Collection lookup with identical data.

    # server
    MyUsers = new Mongo.Collection 'myusers'
    
  7. Copy the user document from Meteor.users() into the MyUsers collection.

  8. Run this on the Meteor server (ALSO UNEXPECTED):

    # anywhere on the server
    if Meteor.isServer
      user_selector = { 'emails': { '$elemMatch': { 'address': /^adm/ } } }
      user_count = MyUsers.find(user_selector).count()
      console.log user_count 
      # prints 0 WHY!?
    

Furthermore, if I publish ALL the users, but run the exact same query against the client side code (e.g. within a template helper param), the query returns the expected count.

II. Pub/Sub Template Helper Case:

  • Publish and subscribe to users.

    # Server
    Meteor.publish 'all_users', ->
      return Meteor.users.find({})
    
    # Client
    Template.people.onCreated ->
      self = @
      self.peopleReady = new ReactiveVar()
      self.autorun ->
        users = Meteor.subscribe 'all_users'
        self.peopleReady.set users.ready()
    
    Template.people.helpers
      user_count: ->
        user_selector = { 'emails': { '$elemMatch': { 'address': /^adm/ } } }
        user_count = Meteor.users.find(user_selector).count()
        console.log user_count 
        # prints 1
        return user_count         
    

Why the difference in the server code demonstrated in I.4 above? I wonder because...

  • EJSON is properly extended.
  • MiniMongo properly selects and counts records on the client.
  • Using a MyUser Collection (instantiated with Mongo.Collection) also fails to report the correct count on the server but runs successfully on the client using the extended RegExp EJSON type in this query selector { 'emails': { '$elemMatch': { 'address': /^adm/ } } } with identical documents outside the scope of Meteor.user

Where can I see (and experiment with) the server side definition of Collection.find() inside the Meteor source code?

1
Seems to work fine for me on the server using a meteor shell session. - MasterAM
Can you try using $regex operator instead of the java script expression. It may be a bug that is documented somewhere. - BatScream
@BatScream - No, the $regex operator does not work inside an array lookup (e.g. '$in': [/foo/gi, /bar/gi, 'baz']) so that's not an option. Also note that the EJSON types are properly extended and work well on the client side. I'd like to fix the bug in any case. - 4Z4T4R
Did you try with $elemMatch? Not with $in. - BatScream
@BatScream - Yes, that's the example in the OP. RegExp needs to work for both. - 4Z4T4R

1 Answers

0
votes

This does look like a bug. Please file an issue at http://github.com/meteor/meteor/issues . Be sure to follow our reproduction guidelines.