1

I want to realise an online editor like plunker. I have defined the following data structure: a post (ie, a project) contains a list of folders (which means different versions of the post), and a folder is just a list of files.

var PostSchema = new mongoose.Schema({
  folders: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Folder' }]
  ...
});

var FolderSchema = new mongoose.Schema({
    files: [{ name: String, body: String, editorOption: Object }],
    post: { type: mongoose.Schema.Types.ObjectId, ref: 'Post' }
})

I want to use the following request to add a folder/version (by the save button on the editor). Note that, because a post can be opened in different places at the same time, we have to fetch the post from the database before adding a version to it, then we return the up-to-date post to the controller.

o.addFolder = function (id, folder) {
    return $http.post('/posts/' + id + '/editor/folders', folder, {
        headers: { Authorization: 'Bearer ' + auth.getToken() }
    })
}

router.post('/posts/:post/editor/folders', auth, function (req, res, next) {
    req.post.populate('folders', function (err, post) {
        if (err) return next(err);
        var folder = new Folder(req.body);
        folder.post = post;
        folder.save(function (err, folder) {
            if (err) return next(err);
            console.log("3 folder: "); console.log(folder);
            console.log("4 post: "); console.log(post);
            post.folders.push(folder);
            console.log("5 folder: "); console.log(folder);
            console.log("6 post: "); console.log(post);
            post.save(function (err, post) {
                if (err) return next(err);
                res.json({ folder: folder, post: post })
            })
        })
    })
});

Here is a test log which tries to add a folder of 2 files to an empty post:

3 folder: 
{ __v: 0,
  post: 
   { _id: 58b5e86d8e328f58f3e87ac2,
     __v: 0,
     folders: [] },
  _id: 58b5e86d8e328f58f3e87ac3,
  files: 
   [ { name: 'index.html',
       body: '<!DOCTYPE html>\n<body>\nindex.html\n</body>\n</html>',
       editorOption: [Object],
       _id: 58b5e86d8e328f58f3e87ac5 },
     { name: 'script.js',
       body: '',
       editorOption: [Object],
       _id: 58b5e86d8e328f58f3e87ac4 } ] }
4 post: 
{ _id: 58b5e86d8e328f58f3e87ac2,
  __v: 0,
  folders: [] }
5 folder: 
events.js:85
      throw er; // Unhandled 'error' event
            ^
RangeError: Maximum call stack size exceeded

Does anyone know what's wrong there?

SoftTimur
  • 5,630
  • 38
  • 140
  • 292
  • It means that you're experiencing unbounded recursion, although after glancing at the code its not immediately obvious (at least to me) where... its also a bit hard to follow because of all the variable shadowing you're doing. – Jared Smith Feb 28 '17 at 19:46
  • They are nested callbacks, I don't see how recursion is possible... – SoftTimur Feb 28 '17 at 19:49
  • It almost has to be the last call `res.json(...` otherwise you'd see 'here' printed over and over in devtools until you got the error for overflowing the call stack... unless its happening somewhere in code you didn't post. – Jared Smith Feb 28 '17 at 19:53
  • My tests show it can not display log after `post.folders.push(folder);` – SoftTimur Feb 28 '17 at 21:20
  • Hey SoftTimur I found some posts that have similar issues. http://stackoverflow.com/questions/16810449/when-to-use-next-and-return-next-in-node-js 'Unhandled error event' for me points to how you are handling unresolved callbacks. http://stackoverflow.com/questions/5384526/javascript-node-js-next Does writing return next() instead of return next(err) help with the error handling? – Matt Fernandez Mar 01 '17 at 04:33

1 Answers1

1

The following code accomplishes what I want. Apparently, req.post.folders.push(folder) can push folder to the up-to-date post. And we do populate in the end.

router.post('/posts/:post/editor/folders', auth, function (req, res, next) {
    var folder = new Folder(req.body);
    folder.post = req.post;
    folder.save(function (err, folder) {
        if (err) return next(err);
        req.post.folders.push(folder);
        req.post.save(function (err, post) {
            if (err) return next(err);
            req.post.populate('folders', function (err, post) {
                if (err) return next(err);
                res.json(post);
            })
        })
    })
});
SoftTimur
  • 5,630
  • 38
  • 140
  • 292