13

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);  
Shakirullahi Logico
  • 249
  • 1
  • 2
  • 10

2 Answers2

23

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.

bkapicka
  • 315
  • 3
  • 4
  • 15
    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".` – s-ol Feb 15 '15 at 19:50
  • 1
    I'm also facing the same problem as @S0lll0s. Option 1 does not seem to work. – ramdog Mar 08 '15 at 22:48
  • @ramdog 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). – s-ol Mar 08 '15 at 22:51
  • 1
    @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` (https://www.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. – ramdog Mar 09 '15 at 04:21
  • No, I don't use that - guess I'll have to check my plugins and retry too. – s-ol Mar 09 '15 at 05:58
  • 1
    @ramdog 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. Sabari – sabari Jul 11 '15 at 16:07
  • 1
    @sabari - No. If you're curious about a longer discussion on the subject: https://github.com/Automattic/mongoose/issues/2772. – ramdog Jul 29 '15 at 07:37
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);
})
  • 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 ? – kamran alam May 18 '21 at 19:32