Closed MikeShi42 closed 6 years ago
@MikeShi42 Thanks for the clear explanation!
here's the repro script ( based on @MikeShi42's code ) I used to work on this:
#!/usr/bin/env node
'use strict';
const assert = require('assert');
const mongoose = require('mongoose');
// mongoose.set('debug', true);
var opts = {};
if (mongoose.version.charAt(0) === '4') {
mongoose.Promise = global.Promise;
opts.useMongoClient = true;
}
mongoose.connect('mongodb://localhost/test', opts);
const conn = mongoose.connection;
const Schema = mongoose.Schema;
const schema = new Schema({
first: String,
last: String,
f: {
type: Boolean,
default: false
},
t: {
type: Boolean,
default: true
}
});
const Test = mongoose.model('test', schema);
const test = new Test({
first: 'George'
});
async function run() {
process.stdout.write(`${mongoose.version}: `);
await conn.dropDatabase();
let saved = await test.save();
assert.strictEqual(saved.t, true, 't: new docs should have defaults set');
assert.strictEqual(saved.f, false, 'f: new docs should have defaults set');
await Test.collection.update({}, { $unset: { f: true, t: true } });
let raw = await Test.collection.findOne();
assert.strictEqual(raw.t, undefined, 't: update should have unset');
assert.strictEqual(raw.f, undefined, 'f: update should have unset');
let found = await Test.findOne();
found.last = 'Boole';
await found.save();
let final = await Test.collection.findOne();
assert.strictEqual(final.t, true, 't: failed to set t = true on save()');
assert.strictEqual(final.f, false, 'f: failed to set f = false on save()');
console.log();
return conn.close();
}
run().catch(error);
function error(e) {
console.error(e.message);
return conn.close();
}
issues: ./6477.js
5.1.1: f: failed to set f = false on save()
issues:
@lineus I guess a question is why defaults are being set on save anyways? Doesn't the documentation say that they should only be set on insert? (I could be totally wrong, but that's been my interpretation).
Personally I'm fine with either behavior, just a bit perplexed :)
@MikeShi42 I agree, the docs and the behavior don't match. I was playing around with this some to determine how far back it goes:
#!/usr/bin/env node
'use strict';
const assert = require('assert');
const mongoose = require('mongoose');
// mongoose.set('debug', true);
var opts = {};
if (mongoose.version.charAt(0) === '4') {
mongoose.Promise = global.Promise;
opts.useMongoClient = true;
}
mongoose.connect('mongodb://localhost/test', opts);
const conn = mongoose.connection;
const Schema = mongoose.Schema;
const schema = new Schema({
first: String,
last: {
type: String,
default: 'Boole'
},
t: {
type: Boolean,
default: true
}
});
const Test = mongoose.model('test', schema);
async function run() {
process.stdout.write(`${mongoose.version}: `);
await conn.dropDatabase();
await Test.collection.insert({});
let found = await Test.findOne();
found.first = 'George';
await found.save();
let final = await Test.collection.findOne();
assert.strictEqual(final.t, true, 't: failed to set t = true on save()');
assert.strictEqual(final.last, 'Boole', 't: failed to set t = true on save()');
console.log('works!');
return conn.close();
}
run().catch(error);
function error(e) {
console.error(e.message);
return conn.close();
}
issues: describe nim
function nim # 'install a version of mongoose [ defaults to latest ]'
{
ver=${1:-'@latest'}
npm install mongoose${ver} >/dev/null 2>&1
}
issues: for ver in 4.8.0 4.13.12 5.0.0 5.1.1 ;do nim @$ver && ./6477.js;done
4.8.0: works!
4.13.12: works!
5.0.0: works!
5.1.1: works!
issues:
I plan to update the docs to reflect the actual behavior, and I think adding a schema option that turns off this behavior could be useful. Changing the current behavior to match the docs could backwards break stuff for folks, but it's worth a think for ver 6.
What do you think @vkarpov15 ?
@lineus thanks for digging deeply and writing all these tests! really appreciated and good to know that the current behavior involving defaults will be the same moving forward :)
Good catch @lineus , thanks for the detailed investigation :+1:
Do you want to request a feature or report a bug? Bug
What is the current behavior? Given a doc that was created before a new boolean schema field was added, if the boolean schema field is set to
default: false
, it will not be set to false. However, if it isdefault: true
, it will be set to true. This is probably clearer looking at the example.If the current behavior is a bug, please provide the steps to reproduce.
The console.log statement will print:
However looking at the db from mongo shell and mongo compass db:
What is the expected behavior?
Honestly I'm not sure, the default value docs seem to state that none of the fields should be updated to the default value since default only applies on insert, unless
setDefaultsOnInsert
. But it seems like it's being applied anyways, no idea why, but it should at least be consistent betweendefault: true
anddefault: false
.Please mention your node.js, mongoose and MongoDB version.