4

I'm trying to populate a tag with the tutorials that are related to it, when I use .populate() on the query it works, but when I do it directly on the model I have an inifite loop.

Here's my code:

Tag.js

const mongoose = require("mongoose");

const tagSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: true,
      unique: true,
      trim: true
    }
  },
  {
    toObject: { virtuals: true },
    toJSON: { virtuals: true }
  }
);

tagSchema.virtual("tutorials", {
  ref: "Tutorial",
  foreignField: "tags",
  localField: "_id"
});

tagSchema.pre(/^find/, function(next) {
  // That's the code that causes an infinite loop
  this.populate({
    path: "tutorials",
    select: "-__v"
  });

  next();
});

const Tag = mongoose.model("Tag", tagSchema);

module.exports = Tag;

Tutorial.js

const mongoose = require('mongoose');

const tutorialSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
    unique: true,
    trim: true
  },
  tags: {
    type: [
      {
        type: mongoose.Schema.ObjectId,
        ref: 'Tag'
      }
    ]
  }
});

const Tutorial = mongoose.model('Tutorial', tutorialSchema);

module.exports = Tutorial;

I'd like to know what causes the infinite loop and why does it work on the query but not on the model ? Thanks !

Edit

Here's the code that works

Tag.js

const mongoose = require("mongoose");

const tagSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: true,
      unique: true,
      trim: true
    }
  },
  {
    toObject: { virtuals: true },
    toJSON: { virtuals: true }
  }
);

tagSchema.virtual("tutorials", {
  ref: "Tutorial",
  foreignField: "tags",
  localField: "_id"
});

const Tag = mongoose.model("Tag", tagSchema);

module.exports = Tag;

Tutorial.js

const mongoose = require('mongoose');

const tutorialSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
    unique: true,
    trim: true
  },
  tags: {
    type: [
      {
        type: mongoose.Schema.ObjectId,
        ref: 'Tag'
      }
    ]
  }
});

const Tutorial = mongoose.model('Tutorial', tutorialSchema);

module.exports = Tutorial;

TagController.js

const Tag = require('./../models/tagModel');

exports.getAllTags = async (req, res) => {
  try {
    const docs = await Tag.find().populate({
      path: 'tutorials',
      select: '-__v'
    });

    res.status(200).json({
      // some code
    });
  } catch(err) => {
    // some code
  }
});
sabrina
  • 41
  • 3
  • Can you add the codes for these? `when I use .populate() on the query it works, but when I do it directly on the model I have an inifite loop.` When you update the question tag me with @SuleymanSah so that I am informed. – SuleymanSah Feb 02 '20 at 09:55
  • @SuleymanSah Thanks for your answer, I added the code you asked for – sabrina Feb 02 '20 at 21:56
  • Sabrina can you please explain when does problem occurs? Show the code that causes error. I am trying to replicate the error with no success. Also can you tell which mongoose version do you use? – SuleymanSah Feb 03 '20 at 09:37
  • @SuleymanSah It's in the Tag model middleware that populates tags that causes an infinite loop – sabrina Feb 04 '20 at 16:36
  • What version do you use for mongoose? Also is it this query that causes problem `const docs = await Tag.find().populate({ path: 'tutorials', select: '-__v' });`? – SuleymanSah Feb 04 '20 at 16:44
  • @SuleymanSah Yes it's that one, mongoose version: 5.7.13 – sabrina Feb 04 '20 at 17:13
  • Really interesting I can't reproduce this error, can you show me a few tags document? – SuleymanSah Feb 04 '20 at 17:52
  • @SuleymanSah { "color": "orange", "_id": "5e32ae88f57dbc5c44905f62", "name": "javascript", "slug": "javascript", "__v": 0, "id": "5e32ae88f57dbc5c44905f62" } – sabrina Feb 07 '20 at 11:03

2 Answers2

1

I ran into the same problem recently and spent quite a while to figure it out, in my case two queries are populating each other and causes infinite loop.

Steven Lu
  • 11
  • 1
  • 1
0

It happened to me, because I was just console.log({this : this}) or console.log(this) in the virtual middleware