Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose - Should I add refs to parent docs, child docs, or both?

I have two mongodb collections, let's call them parents and children. This parents/children design has a one-to-many relationship, and when I query the parent I want the children as well. It makes sense to have this model design:

var ParentSchema = new Schema({
    name: String,
    children: [{type: Schema.Types.ObjectID, ref: 'Child'}]
});

var ChildSchema = new Schema({
    name: String
});

That way, I can use populate() to easily get the children within the parent. However, I've been told that it's not good to use arrays like this, because they can get cluttered. So, if I put the object reference in the ChildSchema, then I can avoid using an array like that.

var ParentSchema = new Schema({
    name: String
});

var ChildSchema = new Schema({
    name: String,
    parent: {type: Schema.Types.ObjectID, ref: 'Parent'}
});

But if I want to get the children withing the parent again, populate() won't work. What's the best pattern to use, and if I'm using refs in the children, is there a method similar to populate() that does this? I don't like having to make two queries to get one result.

like image 432
Alex Wohlbruck Avatar asked Nov 29 '16 23:11

Alex Wohlbruck


1 Answers

My understanding is that the issue with storing an array of references to Children within Parents would be the case where the array of Children is unbounded. If this is not the case, I believe that storing an array of references to Children within Parents is the recommended pattern. In the case that the number of children is very large or unbounded, the docs suggest using Virtuals.

I believe a simple example would look something like...

const ChildSchema = new Schema({
  name: String,
  parent: String,
});

const ParentSchema = new Schema({
  name: String,
});

ParentSchema.virtual('children', {
  ref: 'Child',   // the model to use
  localField: 'name',  // find children where 'localField' 
  foreignField: 'parent' // is equal to foreignField
});


const Parent = mongoose.model('Parent', parentSchema);
const Child = mongoose.model('Child', childSchema);

/*
 Let's say we have two parents: Jack and Mindy
 And four children: Jake with Jack, and Mike, Molly, and Mildred with Mindy
*/

Parent.find({}).populate('children').exec(function(error, parents) {
  /// parents.children is now an array of instances of Child. 
});

For more info on population, check out the Mongoose.js docs here mongoosejs.com.

All credit to mongoosejs.com as my example is just an adaptation of theirs. Also, please note that I haven't actually tested this code as I am answering this question on my phone.

Hope this helps.

like image 200
quarterpi Avatar answered Nov 15 '22 08:11

quarterpi