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

Question: I'm getting an array of ids on the populate transform callback #14073

Closed
1 task done
aletorrado opened this issue Nov 10, 2023 · 6 comments
Closed
1 task done
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@aletorrado
Copy link

aletorrado commented Nov 10, 2023

Prerequisites

  • I have written a descriptive issue title

Mongoose version

6.11.1

Node.js version

18.17.1

MongoDB version

5.0

Operating system

Linux

Operating system version (i.e. 20.04, 11.3, 10)

Ubuntu 22.04

Issue

Hi, I'm not sure if this is a bug, or just expected behavior is some case, so I'm posting this as a Help topic.

I'm using the transform callback to leave the id when the object being populated isn't found, but I found that the id argument (the 2nd argument) sometimes is not a single id, but an array of ids.

This doesn't seems to be documented.

Can you please clarify about this? Thanks in advance!

@aletorrado aletorrado added help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary help wanted labels Nov 10, 2023
@aletorrado
Copy link
Author

aletorrado commented Nov 11, 2023

Update:

This seems to happen when populating a reference in a subdocument. For example:

const mySchema = mongoose.Schema({
  name: { type: String, },
  items: [{
    _id: false,
    name: { type: String, set: (x)=>x||null },
    brand: { type: mongoose.Schema.Types.ObjectId, ref: 'Brand' },
  }],
})

const myModel = mongoose.model('MyModel', mySchema)

mongoose.model('MyModel')
.findOne()
.populate([
  {
    path: 'items.brand',
    transform: (doc, id)=>{
      console.log(doc, id) // this prints an array for the id parameter
    },
  }
])
.exec()

This does NOT happen with arrays of references, just with references on subdocuments.

I've also just tested this on the latest 8.0.0 version of mongoose, and it's still happening.

@chumager
Copy link

Hi, you must populate items and brand, not like that... you're populating items.brand

mongoose.model('MyModel')
.findOne()
.populate({
  path: 'items',
  populate: 'brand', //NOTE: you must populate the brand here AFAIK.
  transform: (doc, id)=>{
    console.log(doc, id) // this prints an array for the id parameter
  }
})
.exec() //the "exec" is a helper, you can use await without exec() 

@aletorrado
Copy link
Author

aletorrado commented Nov 13, 2023

Hi, you must populate items and brand, not like that... you're populating items.brand

mongoose.model('MyModel')
.findOne()
.populate({
  path: 'items',
  populate: 'brand', //NOTE: you must populate the brand here AFAIK.
  transform: (doc, id)=>{
    console.log(doc, id) // this prints an array for the id parameter
  }
})
.exec() //the "exec" is a helper, you can use await without exec() 

I don't think so. I'm not doing a nested two-level population, just populating a reference into a subdocument. In any case, the docs says that the 2nd parameter should be an ObjectId. I don't understand the rationale of this behavior, but if this makes sense somehow, it should be documented.

Also, I'm running exec to execute the query while avoiding top-level awaits.

@chumager
Copy link

Oh sorry I read wrong, AFAIR, I always populate after getting the doc, so you can use a post('find', fn()) after the query to populate, but maybe it'll give a promise of promise.

mongoose.model('MyModel')
.findOne()
.post(async function(doc){
  await doc.items.populate("brand"))
})
.exec()

if this ain't work, maybe you should have to spread the items before populate.

Regards.

@vkarpov15
Copy link
Collaborator

I can confirm that .populate('items.brand') is correct in this case, .populate({ path: 'items', populate: 'brand' }) is incorrect because items is a document array, not an array of references.

@vkarpov15 vkarpov15 added this to the 7.6.7 milestone Nov 17, 2023
@vkarpov15 vkarpov15 added has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue and removed help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary help wanted labels Nov 17, 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 Nov 27, 2023
@IslandRhythms
Copy link
Collaborator

const mongoose = require('mongoose');

const mySchema = mongoose.Schema({
  name: { type: String, },
  items: [{
    _id: false,
    name: { type: String, set: (x)=>x||null },
    brand: { type: mongoose.Schema.Types.ObjectId, ref: 'Brand' },
  }],
});

const brandSchema = mongoose.Schema({
  name: 'String',
  quantity: Number
});

const myModel = mongoose.model('MyModel', mySchema);
const brandModel = mongoose.model('Brand', brandSchema);

async function run() {
  await mongoose.connect('mongodb://localhost:27017');
  await mongoose.connection.dropDatabase();
  await brandModel.create({
    name: 'test',
    quantity: 1
  })
  await brandModel.create({
    name: 'test1',
    quantity: 1
  })
  await brandModel.create({
    name: 'test2',
    quantity: 2
  })
  await brandModel.create({
    name: 'test3',
    quantity: 3
  });
  console.log('created');
  const brands = await brandModel.find();
  console.log('found', brands);
  const test = new myModel({ name: 'Test Model' });
  for (let i = 0; i < brands.length; i++) {
    test.items.push({ name: `${i}`, brand: brands[i]._id });
  }
  await test.save();
  console.log('pushed and saved');
  await myModel
  .findOne()
  .populate([
    {
      path: 'items.brand',
      transform: (doc, id)=>{
        console.log('doc', doc, 'associated id', id) // this prints an array for the id parameter
      },
    }
  ]);
}

run();

vkarpov15 added a commit that referenced this issue Dec 1, 2023
…y when populating a justOne path under an array

Fix #14073
vkarpov15 added a commit that referenced this issue Dec 1, 2023
vkarpov15 added a commit that referenced this issue Dec 3, 2023
Call transform object with single id instead of array when populating a justOne path under an array
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

4 participants