Search code examples
node.jsmongodbmongoose

How to refer to a sub collection from another collection in MongoDB/Mongoose?


I have a collection in mongo, let's call it Parent, with a property called children, something like this

const ParentSchema = mongoose.Schema({
children: [{
//children properties
}],
//other collection properties

When I save a record in this collection, every child gets an objectId like this

"_id" : ObjectId("63ba8421f2f128e2f8e6916d")

Then I have a collection called Report. In this collection I can refer to Parent like this

const ReportSchema = mongoose.Schema({
    parent: {
        type: mongoose.Schema.Types.ObjectId,
        ref: "Parent",
        required: false
    },

is there a way to define in this collection a field that refers to children, in order to create a record referring to a specific child? Or should I just use a string field and store the child id in there?

The idea would be to endup with records in Report like

{
    "_id" : ObjectId("63bc482afde665158cd71a41"),
    "createdBy" : ObjectId("63b9d635e6225fa0ff29f316"),
    "parent" : ObjectId("63bbac19fde665158cd718e9"),
    "child" : ObjectId("63ba83eef2f128e2f8e69140"),
// other properties
}

Solution

  • Mongoose's ref property won't work for this, since it takes a model name, a Model, or a function that returns a model name or model but you aren't modeling children (doing so would imply storing them in a separate collection, not as an array on parent documents).

    You can still just have a childId field of ObjectId type and put the child's ID there (you said string, but ObjectId is more appropriate) without declaring it as a ref, i.e.

    const ReportSchema = mongoose.Schema({
      parent: {
        type: mongoose.Schema.Types.ObjectId,
        ref: "Parent",
        required: false
      },
      child: mongoose.Schema.Types.ObjectId,
    }
    

    However you wouldn't be able to populate() the child field since mongoose's populate features would require there to be a separate Child model/collection.

    You would of course be able to populate the parent field, then write code to pull the child document out of the populated parent's children array. You could also write a custom aggregation pipeline to do this on the DB side of the wire.

    But your best best may be to bite the bullet and make a ChildSchema, a Child model, use that as a ref in Parent's children array, and then you can also use it as a ref for a child field in ReportSchema and mongoose's population features will work for it.