mongoose - ObjectId that references a Sub-Document
Asked Answered
D

2

14

Would it be possible for an ObjectId in ModelA to reference a sub-document in modelB?

var C = new Schema({...});  
var B = new Schema({c: [C]});  
var A = new Schema({c: { type: ObjectId, ref: 'ModelB.ModelC' });  

var Model_A = mongoose.model('ModelA', A);  
var Model_B = mongoose.model('ModelB', B);  
var Model_C = mongoose.model('ModelC', C);  
Dower answered 20/7, 2014 at 18:6 Comment(0)
S
24

Yes it is possible, but you have a few options.


Option 1: C as a Subdocument

If you really want to use subdocuments, you don't need to create a separate model. You need to change your reference to the 'c' array.

var C = new Schema({...});  
var B = new Schema({c: [C]});  
var A = new Schema({c: { type: ObjectId, ref: 'ModelB.c' });  

var Model_A = mongoose.model('ModelA', A);  
var Model_B = mongoose.model('ModelB', B); 

Option 2: C as a Model

(I only present this as an alternative - since your example seems redundant since you create 'C' as a separate Model as well as a subdocument)

Alternatively, it may make sense to have separate collections, you can create a mongoose model for each. Each will be a separate collection:

var Model_A = mongoose.model('ModelA', A);  
var Model_B = mongoose.model('ModelB', B);  
var Model_C = mongoose.model('ModelC', C);

In this case you may want to directly reference each model:

var C = new Schema({...});  
var B = new Schema({c: { type: ObjectId, ref: 'ModelC' }});  
var A = new Schema({c: { type: ObjectId, ref: 'ModelC' }); 

The Point

Yes its possible, but you need to pick if you want C as a model or subdocument.

Silverside answered 12/11, 2014 at 17:51 Comment(7)
the first solution doesn't work for me. In my case model B and C are the same though (User has a list of friendships in friends and every friendship has a reference to it's other-direction-counterpart). I get this: MissingSchemaError: Schema hasn't been registered for model "User.friends".Backdrop
I'm also facing the same problem as @S0lll0s. Option 1 does not seem to work.Rambort
@Rambort I still haven't found a solution that allows me to populate a subdocument-self-reference, I just use a "blank" ObjectId and search for it on my own. Let me know if you find something, but I am tempted to believe there is no solution (yet).Backdrop
@S0lll0s - thanks for the update. I actually think there was something else that was causing this misleading error for my scenario - I was trying to use the NPM module mongoose-id-validator (npmjs.com/package/mongoose-id-validator). Have you been by chance using that, too? I removed the use of that plugin and Option 1 above indeed works.Rambort
No, I don't use that - guess I'll have to check my plugins and retry too.Backdrop
@Rambort Is Option 1, you have described in the post working for you? If so can you pls post a sample here. Sorry, I am afraid to start a new thread, because I dont see this kind of answer any where. So I want to reach you. I am getting error like "Schema hasn't been registered for model". Please help. Thanks. SabariImitative
@Imitative - No. If you're curious about a longer discussion on the subject: github.com/Automattic/mongoose/issues/2772.Rambort
M
4

It's been 7 years but I faced the same issue, I found the plugin mongoose-sub-references-populate to populate subdocuments.

const subReferencesPopulate = require('mongoose-sub-references-populate');

var B = new Schema({c: [C]});  
var A = new Schema({c_inA: { type: ObjectId, subRef: 'ModelB.c' });  

A.plugin(subReferencesPopulate);
var Model_A = mongoose.model('ModelA', A);  
var Model_B = mongoose.model('ModelB', B);  

Model_A.findById(_id,async (error, res)=>{
  await res.subPopulate('c_inA');
  console.log(res);
})
Margaritamargarite answered 3/5, 2021 at 16:40 Comment(1)
I have a slightly different scenario: var B = new Schema({ c: { alpha: { beta: [BETA] }}}); var A = new Schema({ l1: { l2: { beta_inA: { type: ObjectId, subRef: 'ModelB.c.alpha.beta' }}}}); Model_A.findById(_id,async (error, res)=>{ await res.subPopulate('HOW_TO_POINT_TO_beta_inA_HERE ??'); console.log(res); }); How to point to beta_inA in subPopulate ?Carolyncarolyne

© 2022 - 2024 — McMap. All rights reserved.