Дождитесь результата forEach перед отправкой обратного вызова на главную - PullRequest
0 голосов
/ 15 марта 2019

Я хочу собрать данные с его дочерним элементом (еще один элемент, связанный с этим идентификатором продукта). У меня есть коллекция с этой схемой

// User Schema
const filtersSchema = mongoose.Schema({
    filter_name:{
        type: String,
        required: true
    },
    filter_code:{
        type: String,
        required: true,
        unique: true
    },
    bind_to: {
        type: Schema.Types.ObjectId,
        default: null
    },
    filter_status:{
        type: Boolean,
        default: true
    },
    created_on:{
        type: Date,
        default: Date.now
    },
    updated_on:{
        type: Date,
        default: Date.now
    }
});

Если я введу в нее данные, значение bind_to по умолчаниюбудет нулевым, это означает, что его родитель.Если я отправлю bind_to ID родителя, это будет ObjectID.

Я хочу собрать такие данные, как это

[{
-- parent object --
children:[
  {
  -- child object --
  },
  {
  -- child object --
  }
]
}]

, если у нас более одного элемента, он пройдетцикл (forEach), но обратный вызов отправляется до завершения цикла forEach.Я знаю, что forEach является асинхронным, и запрос является синхронным.но вы не знаете, как это сделать!

вы можете увидеть модуль ниже

// Get Filters by Parent ID
module.exports.getFiltersByParentId = (pid, callback) => {
    Filters.find({bind_to: pid}, callback);
}

//For getting the parent object and looping it to get its child objects
module.exports.getFilters = (callback, limit) => {
    Filters.find({bind_to: null}, (err, filters) => {
        if (err) {
            console.log(err);
            let obj = {status: false, error: err.errmsg};
            callback(obj);
        } else {
            const resObj = [];
            filters.forEach(async function (ele) {
                await Filters.getFiltersByParentId(ele._id, (err, cfil) => {
                    if (err) {
                        let obj = {status: false, message: err.errmsg};
                        callback(obj);
                    } else {
                        console.log(ele, "Obj");
                        ele.children = cfil;
                        resObj.push(ele);
                    }
                });
            });
            Promise.all(resObj).then(res => {
                let obj = {status: true, data: res, message: "Filters found"};
                callback(obj);
            });
        }
    });
}

, но в этом случае объект результата будет пустым.Как я могу получить правильный объект со значениями, как указано выше?

Даже я пытался с этим методом

const resObj = [];
            filters.map(function (ele) {
                Filters.getFiltersByParentId(ele._id, (err, cfil) => {
                    if (err) {
                        let obj = {status: false, message: err.errmsg};
                        callback(obj);
                    } else {
                        console.log(ele, "Obj");
                        ele.children = cfil;
                        resObj.push(ele);
                    }
                });
            });
            Promise.all(resObj).then(res => {
                let obj = {status: true, data: res, message: "Filters found"};
                callback(obj);
            });

И это

Promise.all(filters.map(function (ele) {
                Filters.getFiltersByParentId(ele._id, (err, cfil) => {
                    if (err) {
                        let obj = {status: false, message: err.errmsg};
                        callback(obj);
                    } else {
                        console.log(ele, "Obj");
                        ele.children = cfil;
                        resObj.push(ele);
                    }
                });
            })).then(res => {
                let obj = {status: true, data: res, message: "Filters found"};
                callback(obj);
            });

Хорошо, теперь явозвращая обещание от getFiltersByParentId

module.exports.getFiltersByParentId = (pid, callback) => {
    return new Promise(function(resolve, reject) {
        Filters.find({bind_to: pid}, function (err, results) {
            if (err) {
                reject(err);
            } else {
                resolve(results);
            }
        })
    });
}

Ответы [ 2 ]

1 голос
/ 15 марта 2019

Во-первых, поскольку Filters.getFiltersByParentId не возвращает обещание, нет смысла await вводить ответ - поэтому я завернул его в новое обещание - если бы у меня было время, возможно, есть более простой способ сделать этобез использования async / await, поскольку в коде вообще нет никаких обещаний, за исключением обещания, не введенного для использования async / await

Тем не менее, я считаю, что код проще читать таким образом, поэтому, давайте продолжим тему async / await и обещания

Во-вторых, использование цикла for ... of делает код очень простым, особенно если вы хотите, чтобы при любой ошибке прекращались дальнейшие вызовы Filters.getFiltersByParentId

код следующим образом

module.exports.getFilters = (callback, limit) => {

    Filters.find({bind_to: null}, async (err, filters) => {
        if (err) {
            console.log(err);
            let obj = {status: false, error: err.errmsg};
            callback(obj);
        } else {
            const resObj = [];
            for (const ele of filters) {
                try {
                    let result = await new Promise((resolve, reject) => {
                        Filters.getFiltersByParentId(ele._id, (err, cfil) => {
                            if (err) {
                                let obj = {status: false, message: err.errmsg};
                                reject(obj);
                            } else {
                                console.log(ele, "Obj");
                                ele.children = cfil;
                                resolve(ele);
                            }
                        });
                    });
                    resObj.push(result);
                } catch(e) {
                    return callback(obj);
                }
            }
            let obj = {status: true, data: resObj, message: "Filters found"};
            callback(obj);
        }
    });
};

изменить: у меня было время: p

Вот код без асинхронного / ожидание, так как нет обещаний

module.exports.getFilters = (callback, limit) => {
    Filters.find({bind_to: null}, (err, filters) => {
        if (err) {
            console.log(err);
            let obj = {status: false, error: err.errmsg};
            callback(obj);
        } else {
            const resObj = [];
            const getFilters = (index) => {
                if (index < filters.length) {
                    const ele = filters[index];
                    Filters.getFiltersByParentId(ele._id, (err, cfil) => {
                        if (err) {
                            let obj = {status: false, message: err.errmsg};
                            callback(obj);
                            return;
                        } else {
                            console.log(ele, "Obj");
                            ele.children = cfil;
                            getFilters(index + 1);
                        }
                    });
                } else {
                    let obj = {status: true, data: resObj, message: "Filters found"};
                    callback(obj);
                }
            };
            getFilters(0);
        }
    });
};
0 голосов
/ 15 марта 2019

После внесения некоторых изменений в мой вопрос и использования @ Jaromanda X's & @ CertainPerformance руководства я нашел решение для своего вопроса.это не совсем то, что я хотел, но это совсем тот же вывод.

Я изменил метод g Filters.getFiltersByParentId, чтобы вернуть Promise

module.exports.getFiltersByParentId = (pid, callback) => {
    return new Promise(function(resolve, reject) {
        Filters.find({bind_to: pid._id}, function (err, results) {
            if (err) {
                reject(err);
            } else {
                let obj = {parent: pid, children: results};
                resolve(obj);
            }
        })
    });
}

Затем изменил forEach на array.map и использовалмассив обещаний в Promise.all функции

module.exports.getFilters = (callback, limit) => {
    Filters.find({bind_to: null}, (err, filters) => {
        if (err) {
            console.log(err);
            let obj = {status: false, error: err.errmsg};
            callback(obj);
        } else {
            const resObj = [];
            var promises = [];

            filters.map(function (ele) {
                promises.push(Filters.getFiltersByParentId(ele, (err, cfil) => {
                    if (err) {
                        let obj = {status: false, message: err.errmsg};
                        callback(obj);
                    } else {
                        console.log(ele, "Obj");
                        ele.children = cfil;
                        resObj.push(ele);
                    }
                }));
            });

            Promise.all(promises).then(res => {
                let obj = {status: true, data: res, message: "Filters found"};
                callback(obj);
            });

        }
    });
}

Наконец, мой вывод выглядит примерно так

[
 {
  parent: {
   --- parent object ---
  },
  children: [
    {
     --- child object 1 ---
    },
    {
     --- child object 2 ---
    },
    {
     --- child object n ---
    }
  ]
 }
]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...