skip to Main Content

I have a document which has a field as Array of References and it is refering to the same document. I want to populate all the nested fields.

The Data will be Acyclic (person -> children -> children ≠ person).

The Schema of the Document look like

const personSchema = new mongoose.schema({
  name: {
    type: String,
    required: true,
  },
  [...],
  children: [{
    type: mongoose.Schema.Types.ObjectId,
    ref: "Person",
  }],
});

const Person = mongoose.model("Person", personSchema); 

while finding a person with his/her _id I want that it’s children, children’s children, …. must be populated

Output should look like

{
  "_id": 1,
  "name": "John Doe",
  "children": [
    {
      "_id": 2,
      "name": "Jane Doe",
      "children": [
        {
          "_id": 3,
          "name": "Billy Doe",
          "children": [
            {
              "_id": 4,
              "name": "Bobby Doe"
              [...]
            }
          ]
        }
      ]
    }
  ]
}

2

Answers


  1. Try this recursive function.

    personSchema.methods.populateChildrenRecursively = async function() {
          await this.populate('children').execPopulate();
          for (let child of this.children) {
            await child.populateChildrenRecursively();
          }
        };
    
    Login or Signup to reply.
  2. Mongoose lets you add pre and post hooks as part of their middleware.

    By adding a pre hook to the find middleware you can tell mongoose to always populate the children property and will do so recursively. However, since you only want the populate to happen when a user is searching by _id you need a condition. In the mongoose Query object there is a property called _conditions whose value is an object. So if that object has the _id property you know you are searching using the _id and therefore it won’t populate on any of the other find calls e.g. searching by name etc.

    Based on your schema and _id property it would look like this:

    personSchema.pre('find', function() {
       if('_id' in this._conditions){
          this.populate('children');
       }
    });
    
    const person = await Person.find({_id: 1});
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search