Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using default value on sub documents does not work as expected #14445

Closed
2 tasks done
emiljanitzek opened this issue Mar 18, 2024 · 3 comments · Fixed by #14504
Closed
2 tasks done

Using default value on sub documents does not work as expected #14445

emiljanitzek opened this issue Mar 18, 2024 · 3 comments · Fixed by #14504
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@emiljanitzek
Copy link
Contributor

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Mongoose version

8.2.2

Node.js version

20.11.1

MongoDB server version

6.3.0

Typescript version (if applicable)

No response

Description

We still don't get the correct behaviour with sub documents in our schema with mongoose 8. This it related to #14420 and the fix in #14437 did not resolve the issue.

When setting the nested document to an empty object, this get saved as null in the database. Fetching the document from the database will not fallback to the default empty object.

When setting the nested document to undefined, fetching the document from the database will return the default empty object.

This requires us to manually handle all nested paths to make sure that the values are both saved correct and use the correct return values.

Steps to Reproduce

const mongoose = require('mongoose');

const SubSchema = new mongoose.Schema({
	name: { type: String }
}, { _id: false });

const MainSchema = new mongoose.Schema({
	sub: { 
		type: SubSchema,
		default: {}
	}
});

const MainModel = mongoose.model('Main', MainSchema);

async function run() {
	await mongoose.connect('mongodb://localhost:27017/mongoose_test');
	console.log(mongoose.version);

	const doc = new MainModel({ sub: { name: 'Hello World' } });
	console.log('init', doc.sub); // { name: 'Hello World' }
	await doc.save();

	doc.set({ sub: {} });
	await doc.save();
	console.log('save empty object', doc.sub); // {} OK!

	const savedDocFirst = await MainModel.findById(doc.id).orFail();
	console.log('findById', savedDocFirst.sub); // null WRONG!

	doc.set({ sub: undefined });
	await doc.save();
	console.log('save with undefined', doc.sub); // undefined WRONG!

	const savedDocSecond = await MainModel.findById(doc.id).orFail();
	console.log('findById', savedDocSecond.sub); // {} OK!
}

run().then(() => mongoose.connection.close()).catch((error) => console.error(error));

Expected Behavior

We expect the document to have the same nested value both after save and when fetching the document form the database. And we expect the value to resolve to the default empty object (especially when explicitly setting the value to the default value)

@emiljanitzek
Copy link
Contributor Author

Found and even bigger problem with this behaviour where the sub document gets updated in the database by just updating any other property on the document. Look at the example below. By just changing the name, the sub document gets changed from the default empty object to null.

const mongoose = require('mongoose');

const SubSchema = new mongoose.Schema({
	name: { type: String }
}, { _id: false });

const MainSchema = new mongoose.Schema({
	name: String,
	sub: { 
		type: SubSchema,
		default: {}
	}
});

const MainModel = mongoose.model('Main', MainSchema);

async function run() {
	await mongoose.connect('mongodb://localhost:27017/mongoose_test');
	console.log(mongoose.version);

	const doc = new MainModel({ name: 'foo' });
	console.log('init', doc.sub); // {} OK!
	await doc.save();

	const savedDocFirst = await MainModel.findById(doc.id).orFail();
	console.log('findById', savedDocFirst.sub); // {} OK!

	savedDocFirst.name = 'bar';
	await savedDocFirst.save();

	const savedDocSecond = await MainModel.findById(doc.id).orFail();
	console.log('findById', savedDocSecond.sub); // null WRONG!
}

run().then(() => mongoose.connection.close()).catch((error) => console.error(error));

@emiljanitzek emiljanitzek changed the title The default value of the sub documents does not work Using default value on sub documents does not work as expected Mar 18, 2024
@simonnilsson
Copy link

I'm seeing the same issue, a field of type Mixed and default {} gets set to null on save() when updating other fields. This feels like a regression introduced in recent update.

@simonnilsson
Copy link

Downgrading from 8.2.2 to 8.2.1 seems to solve this issue.

@IslandRhythms IslandRhythms added the confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. label Mar 21, 2024
@vkarpov15 vkarpov15 modified the milestones: 8.2.4, 8.2.5 Mar 22, 2024
vkarpov15 added a commit that referenced this issue Apr 7, 2024
fix(document): make update minimization unset property rather than setting to null
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Projects
None yet
4 participants