Why does this meteor publication go slower when using limit?

16 Views Asked by At

I just "solved" a major performance issue in a Meteor.js application I maintain, but what I did seems completely counter intuitive. My guess is that my confusion has to do with my lack of understanding off MiniMongo, Mongo indexes or some other Mongo query magic.

In my Meteor app, I need to expose a Collection called Rooms. The Room record has some 30 attributes. I have a use case where I really only need 3 of the fields to reactively make a change to my web page (fyi, my web page is rendered with React and I use a useTracker hook to listen for changes to the subscription).

Thinking that less data sent over the wire is better, I wrote this subscription

  Meteor.publish('room_show', function (number) {
    return Rooms.find({ number },
       {
         fields: {
           _id: 1, number: 1, name: 1, foobar: 1, barfoo: 1, etc_more_fields_like_this: 1
         },
         limit 1
       }
  )

The logic here is that only need the fields listed and I just one the one Room record (hence limit 1). BUT to my surprise, this takes some 5 to 30 seconds for my client subscription to update it's mini-mongo (using Meteor tools in Chrome). Less data over the wire and the subscription only returns (limited to) one record.

And yes, I have an index on the "number" field in my Mongo DB.

I switch back to

Meteor.publish('room_show', function (number) { return Rooms.find({ number }) }

and it is lightning fast. This works great for me so I'm going with it for now.

So it seems that limiting the fields, rather than blindly dumping the entire record, has some computational expense. Perhaps there is some Mongo index or some other magic to mitigate that?

But what seriously confuses me is that this

Meteor.publish('room_show', function (number) { 
    return Rooms.find({ number }, { limit: 1 }) 
}

is also super slow, much slower than leaving the limit off.

First, has anyone else experienced this? I don't have a security reason to limit the data, so I'm ok for now, but it seems completely backwards that returning a cursor for all the Rooms records is slower than limiting to one record. And, of course, second, WTF? Why?

I can consider future needs where I do want to only publish certain fields. I would like to do this without this performance hit.

Thanks for any insight.

Some Meteor packages I use: [email protected] [email protected]

And my MongoDB is at version 5.0.13

Any other package relevant?

I tried this initially with lower versions of Meteor and different versions of MongoDB. The same problem and solution was replicable. I considered looking at the react-meteor-data package, but gave up (got bored and lazy). I use "aldeed:collection2" too, and tried with and without it, but that seems orthogonal.

Indexes on the Rooms collection is pretty simple. I haven't tried messing with that. Perhaps having the fields mentioned in the indexes? Is there some use of limit in the indexes (that doesn't seem right).

meteor> db.rooms.getIndexes()
[
  { v: 2, key: { _id: 1 }, name: '_id_' },
  { v: 2, key: { number: 1 }, name: 'number_index' }
]
0

There are 0 best solutions below