Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pushing object to array of references and creating infinite loop #11756

Closed
aleksa6 opened this issue May 3, 2022 · 6 comments
Closed

Pushing object to array of references and creating infinite loop #11756

aleksa6 opened this issue May 3, 2022 · 6 comments
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@aleksa6
Copy link

aleksa6 commented May 3, 2022

Do you want to request a feature or report a bug?
bug

What is the current behavior?
The problem is that here we are creating post with the user object as a creator, and later we push the post object to user.posts. So, our post would look like this

{
  _id: "some post id",
  creator: {
    _id: "some user id",
    posts: [
      {
        _id: "some post id",
        creator: {
          _id: "some user id",
          posts: [ { ... } ],
        },
      },
    ],
  },
}

and this would lead to a "Maximum call stack size exceeded" error, as expected. But this error happens only when user.posts array is empty and when we try to access the user or the post object after we push post to user.posts. If user.posts is not empty or if it is but we do not try to access the user or the post object "Maximum call stack size exceeded" error does not occur.

If the current behavior is a bug, please provide the steps to reproduce.

require("dotenv").config();

const mongoose = require("mongoose");

const Schema = mongoose.Schema;

const User = mongoose.model(
  "User",
  new Schema({
    name: { type: String, required: true },
    posts: [{ type: mongoose.Types.ObjectId, ref: "Post" }],
  })
);

const Post = mongoose.model(
  "Post",
  new Schema({
    creator: { type: Schema.Types.ObjectId, ref: "User" },
  })
);

const MONGODB_URI = process.env.MONGODB_URI;
const userId = mongoose.Types.ObjectId(process.env.USER_ID);

mongoose
  .connect(MONGODB_URI)
  .then(async (result) => {
    const user = await User.findById(userId);

    const post = new Post({ creator: user });
    await post.save();

    user.posts.push(post);
    console.log(user)

    await user.save();
  })
  .catch((err) => console.log(err));

What is the expected behavior?
We should get an error every time our code runs and not just when user.posts array is empty and we try to access the user or the post object.

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.
Node 18.0.0 | Mongoose 6.3.2

@aleksa6 aleksa6 changed the title Pushing reference to array and creating infinite loop Pushing object to array of references and creating infinite loop May 4, 2022
@IslandRhythms IslandRhythms added the can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. label May 4, 2022
@IslandRhythms
Copy link
Collaborator

Modify this script to demonstrate your issue.

const mongoose = require("mongoose");

const {Schema} = mongoose;

const User = mongoose.model(
  "User",
  new Schema({
    name: { type: String, required: true },
    posts: [{ type: mongoose.Types.ObjectId, ref: "Post" }],
  })
);

const Post = mongoose.model(
  "Post",
  new Schema({
    creator: { type: Schema.Types.ObjectId, ref: "User" },
  })
);

async function run() {
    await mongoose.connect('mongodb://localhost:27017');
    await mongoose.connection.dropDatabase();
    await User.create({
        name: 'Test',
        posts: []
    });
    const user = await User.findOne();

    const post = new Post({ creator: user._id });
    await post.save();

    user.posts.push(post);
    console.log(user)

    await user.save();
}

run();

@aleksa6
Copy link
Author

aleksa6 commented May 4, 2022

const mongoose = require("mongoose");

const { Schema } = mongoose;

const User = mongoose.model(
  "User",
  new Schema({
    name: { type: String, required: true },
    posts: [{ type: mongoose.Types.ObjectId, ref: "Post" }],
  })
);

const Post = mongoose.model(
  "Post",
  new Schema({
    creator: { type: Schema.Types.ObjectId, ref: "User" },
  })
);

const getUser = async () => {
  const user = await User.findOne();
  return !user ? await User.create({ name: "Test", posts: [] }) : user;
};

async function run() {
  await mongoose.connect("mongodb://localhost:27017");
  await mongoose.connection.dropDatabase();

  const user = await getUser();

  const post = new Post({ creator: user });
  await post.save();

  user.posts.push(post);
  console.log(user);

  await user.save();
}

run();

Note that I use user object while creating post and not user._id. Also, while adding post to user.posts we push the whole post object and not post._id. This should create infinite loop, but we get an error only if we try to access the value of the user or the post. If we don't try to access their values, everything works fine and both gets added to the database (if user.posts already has one or more values we can even access the user or the post, and everything will work).

@vkarpov15 vkarpov15 added has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue and removed can't reproduce Mongoose devs have been unable to reproduce this issue. Close after 14 days of inactivity. labels May 11, 2022
@vkarpov15 vkarpov15 added this to the 6.3.5 milestone May 11, 2022
@vkarpov15 vkarpov15 added confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. and removed has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels May 21, 2022
@roshdiAlMajzoub
Copy link

roshdiAlMajzoub commented Jul 20, 2022

hello what if i have an array of posts then what to do plz help
how to insert them all in the user.posts

@vkarpov15
Copy link
Collaborator

@roshdiAlMajzoub please provide some code samples that demonstrate what you're trying to do. Seems like you're just looking for user.posts.push(...posts)?

@imengolea
Copy link

const skillsSchema =({
title: String,
description:String,
});

const Skill = mongoose.model('Skill', skillsSchema);

const teacherSchema =({
profession: String,
teacherFName:String,
bornDate: Number,
priceperhour: Number,
videolink:String,
email:String,
password:String,
skills:[skillsSchema],

});

const Teacher = mongoose.model('Teacher', teacherSchema);

app.post('/taddcourse',function(req,res){
const title= req.body.courseTitle;
const discription= req.body.courseBody;
const teacherName= req.body.teacher;

const skill = new Skill({
    title: title,
    description:discription,
});

Teacher.findOne({teacherFName:teacherName}) .then(function(foundTeacher){
    foundTeacher.skills.push(skill);
    foundTeacher.save();
    res.render("teacherdash",{
        teachName:foundTeacher.teacherFName,
        courses: foundTeacher.skills
       })
})
.catch(function(err){
    console.log(err);
  }) 

});

when I try to run the code this error appears
TypeError: Cannot read property 'skills' of null

@vkarpov15
Copy link
Collaborator

@imengolea that's because foundTeacher can be null

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Projects
None yet
Development

No branches or pull requests

5 participants