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:
- Run a Meteor installation with
aldeed:meteor-simple-schema,aldeed:collection2,accounts-password, andejsonat a minimum. - Extend
EJSONby adding theRegExptype usingEJSON.addTypewith these instructions: How to extend EJSON to serialize RegEx for Meteor Client-Server interactions? - Add a Meteor.user with the email address
"[email protected]" 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!?Run this on the MongoDB shell (bypassing Meteor.users):
# mongo shell > db.users.find({ 'emails': { '$elemMatch': { 'address': /^adm/ } } }).count() # prints 1Attempt an independent Mongo.Collection lookup with identical data.
# server MyUsers = new Mongo.Collection 'myusers'Copy the user document from Meteor.users() into the MyUsers collection.
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 ofMeteor.user
Where can I see (and experiment with) the server side definition of Collection.find() inside the Meteor source code?
meteor shellsession. - MasterAM$regexoperator instead of the java script expression. It may be a bug that is documented somewhere. - BatScream'$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