Skip to content

Commit

Permalink
Merge branch 'master' of github.com:Automattic/mongoose
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed Feb 16, 2021
2 parents b4bb52d + aa7b529 commit 94a2a7f
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 3 deletions.
2 changes: 1 addition & 1 deletion lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ Connection.prototype.startSession = _wrapConnHelper(function startSession(option
* @method transaction
* @param {Function} fn Function to execute in a transaction
* @param {mongodb.TransactionOptions} [options] Optional settings for the transaction
* @return {Promise<Any>} promise that resolves to the returned value of `fn`
* @return {Promise<Any>} promise that is fulfilled if Mongoose successfully committed the transaction, or rejects if the transaction was aborted or if Mongoose failed to commit the transaction. If fulfilled, the promise resolves to a MongoDB command result.
* @api public
*/

Expand Down
2 changes: 1 addition & 1 deletion lib/helpers/populate/assignVals.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ function valueFilter(val, assignmentOpts, populateOptions) {
if (populateOptions.justOne === false) {
return [];
}
return val;
return val == null ? val : null;
}

/*!
Expand Down
7 changes: 6 additions & 1 deletion lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -4592,7 +4592,12 @@ function _assign(model, vals, mod, assignmentOpts) {
if (Array.isArray(rawDocs[key])) {
rawDocs[key].push(val);
rawOrder[key].push(i);
} else {
} else if (isVirtual ||
rawDocs[key].constructor !== val.constructor ||
String(rawDocs[key]._id) !== String(val._id)) {
// May need to store multiple docs with the same id if there's multiple models
// if we have discriminators or a ref function. But avoid converting to an array
// if we have multiple queries on the same model because of `perDocumentLimit` re: gh-9906
rawDocs[key] = [rawDocs[key], val];
rawOrder[key] = [rawOrder[key], i];
}
Expand Down
74 changes: 74 additions & 0 deletions test/model.populate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9869,6 +9869,7 @@ describe('model: populate:', function() {
assert.deepEqual(findCallOptions[0].virtuals, ['foo']);
});
});

it('gh-9833', function() {
const Books = db.model('books', new Schema({ name: String, tags: [{ type: Schema.Types.ObjectId, ref: 'tags' }] }));
const Tags = db.model('tags', new Schema({ author: Schema.Types.ObjectId }));
Expand Down Expand Up @@ -9907,4 +9908,77 @@ describe('model: populate:', function() {
assert.ok(!Array.isArray(populatedBooks[0].tags[0].author));
});
});

it('sets not-found values to null for paths that are not in the schema (gh-9913)', function() {
const Books = db.model('books', new Schema({ name: String, tags: [{ type: 'ObjectId', ref: 'tags' }] }));
const Tags = db.model('tags', new Schema({ authors: [{ author: 'ObjectId' }] }));
const Authors = db.model('authors', new Schema({ name: String }));

return co(function*() {
const anAuthor = new Authors({ name: 'Author1' });
yield anAuthor.save();

const aTag = new Tags({ authors: [{ author: anAuthor.id }, { author: new mongoose.Types.ObjectId() }] });
yield aTag.save();

const aBook = new Books({ name: 'Book1', tags: [aTag.id] });
yield aBook.save();

const aggregateOptions = [
{ $match: {
name: { $in: [aBook.name] }
} },
{ $lookup: {
from: 'tags',
localField: 'tags',
foreignField: '_id',
as: 'tags'
} }
];
const books = yield Books.aggregate(aggregateOptions).exec();

const populateOptions = [{
path: 'tags.authors.author',
model: 'authors',
select: '_id name'
}];

const populatedBooks = yield Books.populate(books, populateOptions);
assert.strictEqual(populatedBooks[0].tags[0].authors[0].author.name, 'Author1');
assert.strictEqual(populatedBooks[0].tags[0].authors[1].author, null);
});
});

it('handles perDocumentLimit where multiple documents reference the same populated doc (gh-9906)', function() {
const postSchema = new Schema({
title: String,
commentsIds: [{ type: Schema.ObjectId, ref: 'Comment' }]
});
const Post = db.model('Post', postSchema);

const commentSchema = new Schema({ content: String });
const Comment = db.model('Comment', commentSchema);

return co(function*() {
const commonComment = new Comment({ content: 'Im used in two posts' });
yield commonComment.save();

const comments = yield Comment.create([
{ content: 'Nice first post' },
{ content: 'Nice second post' }
]);

let posts = yield Post.create([
{ title: 'First post', commentsIds: [commonComment, comments[0]] },
{ title: 'Second post', commentsIds: [commonComment, comments[1]] }
]);

posts = yield Post.find().populate({ path: 'commentsIds', perDocumentLimit: 2, sort: { content: 1 } });
assert.equal(posts.length, 2);
assert.ok(!Array.isArray(posts[0].commentsIds[0]));

assert.deepEqual(posts[0].toObject().commentsIds.map(c => c.content), ['Im used in two posts', 'Nice first post']);
assert.deepEqual(posts[1].toObject().commentsIds.map(c => c.content), ['Im used in two posts', 'Nice second post']);
});
});
});

0 comments on commit 94a2a7f

Please sign in to comment.