Q:

How to avoid/prevent infinite recursive call in Node.js?

I have a javascript function in my Node.js application which calls itself to find its level in parent-child hierarchy in MongoDB. A document will try to find its parent and if found will increase the level and goes on till there is no parent found. It looks like the following,
function findLevel(doc, level, callback){
    if(!doc)
        return callback(null, level);
    var query = {
        id: doc.parentID
    };
    model.findOne(query, function(err, parentDoc){
        if(err){
            return callback(err, level)
        };
        return findLevel(parentDoc, level+1, callback);
    })
}

This has high chance of producing infinite recursive calls. One of the scenario is parentID is same as the current doc's id. That can be avoided by including another condition in find query, but still I am worried about I may miss something and it can cause the entire application to crash/kill. Is there a recommended way to avoid/prevent this kind of situation in Node.js? Or can we restrict the level of recursive calls and stop it gracefully like saying the recursive call should go only till this n level?

A:

You could implement cycle detection by making note of all the IDs you encounter during recursion and stopping as soon as an ID has been handled before.
function findLevel(doc, callback) {
    var level = 0, seen = {};

    (function getParent(doc) {
        // proper termination
        if(!doc || !doc.parentID) return callback(null, level);

        // cycle detection
        if (seen.hasOwnProperty(doc.parentID)) return callback(new Error("cycle detected"));
        seen[doc.parentID] = true;

        // recursion
        model.findOne({id: doc.parentID}, function (err, parentDoc) {
            if (err) return callback(err);

            level++;
            getParent(parentDoc);
        });
    })(doc);
}

