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

The default value for subdocument fields is not applied when nested projection is used (find/findOne methods) #13720

Closed
2 tasks done
andrei-mashko opened this issue Aug 11, 2023 · 3 comments
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@andrei-mashko
Copy link

andrei-mashko commented Aug 11, 2023

Prerequisites

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

Mongoose version

> 6.6.0

Node.js version

v18.16.1

MongoDB server version

5.0

Typescript version (if applicable)

No response

Description

By default mongoose applies default values for subdocument fields which are missing in mongoDB (find/findOne methods):

const mongoose = require('mongoose');

const connection = mongoose.createConnection('mongodb://localhost:27015/test');

const subSchema = new mongoose.Schema({
	propertyA: { type: String, default: 'A' },
	propertyB: { type: String, default: 'B' },
});
const userSchema = new mongoose.Schema({
	name: String,
	sub: { type: subSchema, default: () => ({}) },
});
const User = connection.model('User', userSchema);

await User.insertMany([{ name: 'user' }]);
await User.updateMany({}, { $unset: { 'sub.propertyA': '' } });

const projectionDoc = await User.findOne({}, { name: 1, sub: 1 });
console.log(projectionDoc.sub.propertyA); // 'A'

But when the nested projection is used (e.g. 'sub.propertyA') it doesn't apply it.

const nestedProjectionDoc = await User.findOne({}, { name: 1, 'sub.propertyA': 1, 'sub.propertyB': 1 });
console.log(nestedProjectionDoc.sub.propertyA); // undefined

Steps to Reproduce

const mongoose = require('mongoose');

const connection = mongoose.createConnection('mongodb://localhost:27015/test');

const subSchema = new mongoose.Schema({
	propertyA: { type: String, default: 'A' },
	propertyB: { type: String, default: 'B' },
});
const userSchema = new mongoose.Schema({
	name: String,
	sub: { type: subSchema, default: () => ({}) },
});
const User = connection.model('User', userSchema);

const main = async () => {
	await User.insertMany([{ name: 'user' }]);
	await User.updateMany({}, { $unset: { 'sub.propertyA': '' } });

	const leanDoc = await User.findOne({}, {}, { lean: true });
	console.log(leanDoc.sub.propertyA); // undefined

	const projectionDoc = await User.findOne({}, { name: 1, sub: 1 });
	console.log(projectionDoc.sub.propertyA); // 'A'

	const nestedProjectionDoc = await User.findOne({}, { name: 1, 'sub.propertyA': 1, 'sub.propertyB': 1 });
	console.log(nestedProjectionDoc.sub.propertyA); // 'A' for =< 6.0.0; undefined for > 6.6.0

	await connection.close();
};

main();

Expected Behavior

No response

@andrei-mashko andrei-mashko changed the title The default value for subdocument fields is ignored when nested projection is used (find/findOne methods) The default value for subdocument fields is not applied when nested projection is used (find/findOne methods) Aug 11, 2023
@andrei-mashko
Copy link
Author

andrei-mashko commented Aug 11, 2023

Looks like the problem is only relevant to the case when the nested projection is a string.
It works as expected in the following example:

const nestedProjectionDoc = await User.findOne({}, { name: 1, sub: { propertyA: 1 } });
console.log(nestedProjectionDoc.sub.propertyA); // A

@vkarpov15 vkarpov15 added this to the 7.4.4 milestone Aug 14, 2023
@vkarpov15 vkarpov15 added the has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue label Aug 14, 2023
@IslandRhythms IslandRhythms added confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. and removed has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels Aug 16, 2023
@IslandRhythms
Copy link
Collaborator

const mongoose = require('mongoose');


const subSchema = new mongoose.Schema({
	propertyA: { type: String, default: 'A' },
	propertyB: { type: String, default: 'B' },
});
const userSchema = new mongoose.Schema({
	name: String,
	sub: { type: subSchema, default: () => ({}) },
});
const User = mongoose.model('User', userSchema);

const main = async () => {
  await mongoose.connect('mongodb://localhost:27017');
  await mongoose.connection.dropDatabase();
	await User.insertMany([{ name: 'user' }]);
	await User.updateMany({}, { $unset: { 'sub.propertyA': '' } });

	const leanDoc = await User.findOne({}, {}, { lean: true });
	console.log(leanDoc.sub.propertyA); // undefined

	const projectionDoc = await User.findOne({}, { name: 1, sub: 1 });
	console.log(projectionDoc.sub.propertyA); // 'A'

	const nestedProjectionDoc = await User.findOne({}, { name: 1, 'sub.propertyA': 1, 'sub.propertyB': 1 });
	console.log(nestedProjectionDoc.sub.propertyA); // 'A' for =< 6.0.0; undefined for > 6.6.0

	await mongoose.connection.close();
};

main();

@vkarpov15
Copy link
Collaborator

Confirmed that this issue is caused by #12427. Working on a fix.

vkarpov15 added a commit that referenced this issue Aug 22, 2023
@vkarpov15 vkarpov15 modified the milestones: 7.4.4, 6.12.0 Aug 22, 2023
vkarpov15 added a commit that referenced this issue Aug 22, 2023
fix(document): correctly handle inclusive/exclusive projections when applying subdocument defaults
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
Development

No branches or pull requests

3 participants