diff --git a/lib/helpers/populate/assignRawDocsToIdStructure.js b/lib/helpers/populate/assignRawDocsToIdStructure.js index 765d69f06af..67fa17f4c53 100644 --- a/lib/helpers/populate/assignRawDocsToIdStructure.js +++ b/lib/helpers/populate/assignRawDocsToIdStructure.js @@ -78,7 +78,12 @@ function assignRawDocsToIdStructure(rawIds, resultDocs, resultOrder, options, re continue; } - sid = String(id); + if (id?.constructor?.name === 'Binary' && id.sub_type === 4 && typeof id.toUUID === 'function') { + // Workaround for gh-15315 because Mongoose UUIDs don't use BSON UUIDs yet. + sid = String(id.toUUID()); + } else { + sid = String(id); + } doc = resultDocs[sid]; // If user wants separate copies of same doc, use this option if (options.clone && doc != null) { diff --git a/test/model.populate.test.js b/test/model.populate.test.js index 110471823be..0f38ce648bb 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -7,6 +7,7 @@ const start = require('./common'); const assert = require('assert'); +const { randomUUID } = require('crypto'); const utils = require('../lib/utils'); const util = require('./util'); const MongooseError = require('../lib/error/mongooseError'); @@ -11423,4 +11424,43 @@ describe('model: populate:', function() { await m.disconnect(); }); + + it('handles populating UUID fields (gh-15315)', async function() { + const categorySchema = new Schema({ + _id: { type: 'UUID', default: () => randomUUID() }, + name: { type: String, required: true }, + desc: { type: String, required: true } + }); + + categorySchema.virtual('announcements', { + ref: 'Announcement', + localField: '_id', + foreignField: 'categories' + }); + + const announcementSchema = new Schema({ + _id: { type: 'UUID', default: () => randomUUID() }, + title: { type: String, required: true }, + content: { type: String, required: true }, + validUntil: { type: Date, required: true }, + important: { type: Boolean, default: false }, + categories: [{ type: 'UUID', ref: 'Category' }] + }); + + const Category = db.model('Category', categorySchema); + const Announcement = db.model('Announcement', announcementSchema); + + const category = await Category.create({ name: 'Tech', desc: 'Technology News' }); + + await Announcement.create({ + title: 'New Tech Release', + content: 'Details about the new tech release', + validUntil: new Date(), + categories: [category._id] + }); + + const populatedCategory = await Category.findOne({ _id: category._id }).populate('announcements'); + assert.strictEqual(populatedCategory.announcements.length, 1); + assert.strictEqual(populatedCategory.announcements[0].title, 'New Tech Release'); + }); });