Mongoose: Way to populate one field using id value from another field

Created on 3 Aug 2015  路  14Comments  路  Source: Automattic/mongoose

Example schema:

var countrySchema = new mongoose.Schema({
    ...
    capitalId: {
        type: String,
        ref:  'City'
    }
});

capitalId is good name for field with id of capital and capital is good for capital object.
Right now I can't populate capital using id value from capitalId.

So it would be great to be able to specify which field with id value to use for population. I think it's common situation.
Example:

var countrySchema = new mongoose.Schema({
    ...
    capitalId: String,
    capital:   {
        type:  Object,
        ref:   'City',
        field: 'capitalId' // use this field to get object id
    }
});

Most helpful comment

Yes, I can use only capital field for storing id (I use uuid as id not city name) and populated object. But I want to use different fields for id and object (capitalId and capital) :smile:
Example schema:

var countrySchema = new mongoose.Schema({
    ...
    capitalId: String, // only this field is stored in mongodb
    capital:   {
        type:  Object,
        ref:   'City',
        field: 'capitalId' // use capitalId to get object id
    }
});

All 14 comments

Not going to be supported in the near future. You should be able to populate just fine so long as the 'Capital' document's _id field is a string representing the name. There are numerous tickets open for this, for instance #1888

MongoDB schema design aside; this is a classic case where you should not have a separate capital document that you populate. The whole point of using MongoDB is that these static one-to-one relationships typically don't need to be represented using separate collections.

The whole point of using MongoDB is that these static one-to-one relationships 
typically don't need to be represented using separate collections.

Do you mean embedding? It's not that case because I have separate cities collection used for REST API resource.

country.capital is ambiguous value. Is it id of object or full object in code? Sometimes I really need to use only id (there is no need to load the entire object)

Ok, then populate should work fine if you set capital equal to the ObjectId of the corresponding capital. I can't think of any countries off the top of my head that have the same capital city name, but probably better to have the ObjectId be the unique identifier just to be safe :)

Yes, I can use only capital field for storing id (I use uuid as id not city name) and populated object. But I want to use different fields for id and object (capitalId and capital) :smile:
Example schema:

var countrySchema = new mongoose.Schema({
    ...
    capitalId: String, // only this field is stored in mongodb
    capital:   {
        type:  Object,
        ref:   'City',
        field: 'capitalId' // use capitalId to get object id
    }
});

Yeah unfortunately there's no real plan to support this behavior within the next few months. Contributions welcome, but right now there are more pressing concerns - single embedded document support :)

+1
when i selection the items from the relationship field. I want them to display as the captial city name instead of the object id because i dont know what they stand for in the user perspective.

+1
Sometime, if you don't call populate captial, the capital can make the developer confused because it just contain the capital_id

+1
Sometimes, this is the only way to get around some system, ex. all the existing behaviors is expecting captial_id to be an id, and then you want to add additional populate for this id, so the best way is to have another field captial for the populated values.

I couldn't get this working with a virtual, because virtual always runs after the population, so I can't get one field for id and one for values, because they'll all be the same.

there got to be some easy way grab the populate and still keep the id.

:+1:

Where are we on this? Any updates?

Im trying to populate groups product att with numerous product models
But everytime I put a new one in it knocks the old one out

//POST new Product
router.post("/home",function(req,res){
    product.create(req.body.product,function(err,newProduct){                                              //WHY ISNT IT SAVING NEW PRODUCT TO DB
        if(err){console.log(err)}
        else{
            var groupName=newProduct.category;

            group.findOneAndUpdate({name:groupName}, { product: newProduct.id },function(err,found){
                  console.log(found,"FoundCategory Before product Ids in it<<<<<<<<")
                if (err){console.log(err)}
                else{
                    found.product.push(newProduct);        

                    found.save();               
                    console.log(found,"FoundCategory AFTER product Ids in it<<<<<<<<")

                    res.redirect("/home")}
            })

        }
    })
})
`
Any idea why the new product overtakes the old product field in the array and the old one doesnt save?
Below is my group schema
`var groupSchema= new mongoose.Schema({

    name:String,
    image:String,
    product : [{type:mongoose.Schema.Types.ObjectId,
                ref: 'product' }]


})

Try group.findOneAndUpdate({name:groupName}, { $push: { product: newProduct.id } }

So, is there any workaround for using a populated document with an alias?

https://mongoosejs.com/docs/api.html#schema_Schema-virtual

var countrySchema = new mongoose.Schema({
    capitalId: {type:String}
});

countrySchema.virtual('capital',{
    ref: 'City',
    localField: 'capitalId',
    foreignField: '_id',
    justOne: true
});

countrySchema.set('toObject', { virtuals: true });
countrySchema.set('toJSON', { virtuals: true });
Country.find().populate('capital')
Was this page helpful?
0 / 5 - 0 ratings