Skip to content

Commit

Permalink
Ignore undefined fields when inserting/updating in Mongo (#9444)
Browse files Browse the repository at this point in the history
* Ignore undefined fields when inserting/updating in Mongo

The Mongo Node driver that Meteor uses currently replaces
`undefined` field values with `null`, when doing an
insert/update. This approach can lead to unexpected behaviour,
as outlined in #1646, #6051 and several other issues. This commit
configures the default Mongo connection to `ignoreUndefined`
fields, which means `undefined` fields are not inserted/updated,
instead of being inserted/updated as `null`.

Fixes #6051.

* Add PR link to History.md
  • Loading branch information
hwillson authored and benjamn committed Dec 13, 2017
1 parent ae1783b commit ce3885b
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 9 deletions.
8 changes: 8 additions & 0 deletions History.md
@@ -1,5 +1,13 @@
## v.NEXT

* Meteor's Node Mongo driver is now configured with the
[`ignoreUndefined`](http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html#connect)
connection option set to `true`, to make sure fields with `undefined`
values are not first converted to `null`, when inserted/updated. Fields
with `undefined` values are now ignored when inserting/updating.
[Issue #6051](https://github.com/meteor/meteor/issues/6051)
[PR #9444](https://github.com/meteor/meteor/pull/9444)

* The `accounts-ui-unstyled` package has been updated to use `<form />` and
`<button />` tags with its login/signup form, instead of `<div />`'s. This
change helps browser's notice login/signup requests, allowing them to
Expand Down
17 changes: 9 additions & 8 deletions packages/mongo/mongo_driver.js
Expand Up @@ -132,7 +132,8 @@ MongoConnection = function (url, options) {
autoReconnect: true,
// Try to reconnect forever, instead of stopping after 30 tries (the
// default), with each attempt separated by 1000ms.
reconnectTries: Infinity
reconnectTries: Infinity,
ignoreUndefined: true
}, Mongo._connectionOptions);

// Disable the native parser by default, unless specifically enabled
Expand Down Expand Up @@ -549,13 +550,13 @@ MongoConnection.prototype._update = function (collection_name, selector, mod,
! (options.insertedId instanceof Mongo.ObjectID &&
options.generatedId)) {
// In case of an upsert with a replacement, where there is no _id defined
// in either the query or the replacement doc, mongo will generate an id itself.
// in either the query or the replacement doc, mongo will generate an id itself.
// Therefore we need this special strategy if we want to control the id ourselves.

// We don't need to do this when:
// - This is not a replacement, so we can add an _id to $setOnInsert
// - The id is defined by query or mod we can just add it to the replacement doc
// - The user did not specify any id preference and the id is a Mongo ObjectId,
// - The user did not specify any id preference and the id is a Mongo ObjectId,
// then we can just let Mongo generate the id

simulateUpsertWithInsertedId(
Expand All @@ -575,15 +576,15 @@ MongoConnection.prototype._update = function (collection_name, selector, mod,
}
);
} else {

if (options.upsert && !knownId && options.insertedId && isModify) {
if (!mongoMod.hasOwnProperty('$setOnInsert')) {
mongoMod.$setOnInsert = {};
}
knownId = options.insertedId;
Object.assign(mongoMod.$setOnInsert, replaceTypes({_id: options.insertedId}, replaceMeteorAtomWithMongo));
}

collection.update(
mongoSelector, mongoMod, mongoOpts,
bindEnvironmentForWrite(function (err, result) {
Expand Down Expand Up @@ -666,7 +667,7 @@ var simulateUpsertWithInsertedId = function (collection, selector, mod,
// STRATEGY: First try doing an upsert with a generated ID.
// If this throws an error about changing the ID on an existing document
// then without affecting the database, we know we should probably try
// an update without the generated ID. If it affected 0 documents,
// an update without the generated ID. If it affected 0 documents,
// then without affecting the database, we the document that first
// gave the error is probably removed and we need to try an insert again
// We go back to step one and repeat.
Expand Down Expand Up @@ -925,13 +926,13 @@ Cursor.prototype.observeChanges = function (callbacks) {
var ordered = LocalCollection._observeChangesCallbacksAreOrdered(callbacks);

// XXX: Can we find out if callbacks are from observe?
var exceptionName = ' observe/observeChanges callback';
var exceptionName = ' observe/observeChanges callback';
methods.forEach(function (method) {
if (callbacks[method] && typeof callbacks[method] == "function") {
callbacks[method] = Meteor.bindEnvironment(callbacks[method], method + exceptionName);
}
});

return self._mongo._observeChanges(
self._cursorDescription, ordered, callbacks);
};
Expand Down
2 changes: 1 addition & 1 deletion packages/mongo/package.js
Expand Up @@ -9,7 +9,7 @@

Package.describe({
summary: "Adaptor for using MongoDB and Minimongo over DDP",
version: '1.4.0'
version: '1.4.1'
});

Npm.depends({
Expand Down

0 comments on commit ce3885b

Please sign in to comment.