Bulk operations with find queries gives unexpected result

I have been starting to use bulk operations for some heavy data writes including many operations. However I found one thing that scared me.

If I query with the find object with field selector equals to undefined, it seems that it removed the selector and includes all matches. I found out that the following code below actually removes all documents in the collection Testcol.

  const bulkForTest = Testcol.rawCollection().initializeOrderedBulkOp();
  bulkForTest.find({_id: undefined}).remove();
  bulkForTest.execute();

Is this really the correct behaviour?

Yes. In meteor 1.8 the mongo driver had the remove undefined values option set to true. There aren’t any valid use cases for querying by undefined, it usually indicates a bug somewhere in your code, or a misunderstanding about how mongo works with undefined values. But it certainly caused problems when it was released!

There will never be an undefined _id in a standard collection, so no need to check if you need to remove any such documents.

The Meteor change @znewsham is referring to (actually v1.6.1) is here.

I dont think that it is the same?

find() with bulk actually includes all documents if passing an undefined value. I.e. the following queries are identical.

find({_id: undefined}) returns same result as find({})

Seems to be the same thing. From the changelog:

db.privateUserData.find({
    userId: currentUser._id // undefined
});

…
From Meteor 1.6.1 onwards, this query will now return every document in the collection.

By using rawCollection() you are bypassing Meteor’s involvement and going directly to the Node MongoDB driver. The fact that Meteor and the MongoDB driver now agree on the expected outcome just means the change in v1.6.1 was in line with MongoDB expectations.

It also caused some trouble for us back in the day, but at least it standardises behaviour, which must be a Good Thing™ :slightly_smiling_face:

1 Like

Mongo.Collection#rawCollection()

Returns the Collection object corresponding to this collection from the npm mongodb driver module which is wrapped by Mongo.Collection.

The methods (like update or insert ) you call on the resulting raw collection return promises and can be used outside of a Fiber.

So when you call Collection.rawCollection() (or, likewise, Collection.rawDatabase()) you leave the terrain of Meteor collections and interface with the node.js mongodb driver.

Thanks! I always mix up which version this happened on ! Always surprised that such a breaking change would have been on a minor release :man_facepalming:

1 Like