0

I've already called lean() to make sure that I've converted the returned data into a plain object but only stories[x].authorId is not getting added as a property to the current stories[x] object.

Can somebody explain why and provide a solution? Does it have to do with scope or is it that I cannot modify the object within another query?

Story.find({}).sort({created: -1}).lean().exec(function(err, stories) {
    if (err) throw err;
    for(var x=0; x < stories.length; x++) {
        stories[x].commentsLength = stories[x].comments.length; 
        stories[x].created = stories[x]._id.getTimestamp();
        stories[x].timeAgo = timeHandler(stories[x]);
        User.find({'username': stories[x].author}).lean().exec(function(x, err, data) {
            stories[x].authorId = data[0]._id;
                console.log(stories[x]); // authorId is there
        }.bind(this, x));
        console.log(stories[x]); // authorId is not there
    }
    res.render('news', {message: "Homepage", data: stories});
})
Community
  • 1
  • 1
Steven Chen
  • 397
  • 1
  • 6
  • 19

1 Answers1

0

It looks to me that you're trying to log out stories[x] after you call the asynchronous User.find() function. Because User.find() runs asynchronously, you won't have access to its results until the call completes. In other words, this is expected behavior.

Something else of note, you might find your code is easier to read if you use an iterator function like .forEach or even async.each from the module:

Story.find({}).sort({created: -1}).lean().exec(function(err, stories) {
    if (err) throw err;
    stories.forEach(function(story) {
        story.commentsLength = story.comments.length;
        story.created = story._id.getTimestamp();
        story.timeAgo = timeHandler(story);
        User.find({
            'username': story.author
        }).lean().exec(function(x, err, data) {
            story.authorId = data[0]._id;
            console.log(story); // authorId is there, because this means User.find completed
        }.bind(this, x));
        console.log(story); // authorId is not there, and never will be, because this function executes before User.find completes its lookup
    });
    res.render('news', {
        message: "Homepage",
        data: stories
    });
});

If you're attempting to modify the return data, you could use async to ensure all the find functions complete before you execute a callback:

function getStory(callback) {
    Story.find({}).sort({created: -1}).lean().exec(function(err, stories) {
        if (err) throw err;
        async.each(stories, function(story, callback) {
            story.commentsLength = story.comments.length;
            story.created = story._id.getTimestamp();
            story.timeAgo = timeHandler(story);
            User.find({
                'username': story.author
            }).lean().exec(function(x, err, data) {
                story.authorId = data[0]._id;
                callback(err, story);
            }.bind(this, x));
        }, function(err, results) {
            callback(err, results); // results is now an array of modified stories
        });
        res.render('news', {
            message: "Homepage",
            data: stories
        });
    })
}
brandonscript
  • 68,675
  • 32
  • 163
  • 220