Bluebird с мангустом с использованием Promise.Each

Я застрял в функции, с которой работаю (я могу делать все это неправильно). Итак, краткое объяснение, я хочу добавить объемные данные в коллекцию, коллекция называется «Сайты», формат CSV - сайт, страна, тип. Я пытаюсь использовать обещания для этого (Bluebird). Итак, рассмотрим код:

 Promise.each(sites, sites => new Promise((resolve, reject) => {
    //console.log(sites);
    let name = tools.extractDomain(req, res, sites[0]);
    let country = sites[1];
    let group = sites[2];
    if (name != "" && country != "" && group != "") {

        Site.findOne({ name: name }, "_id", function(err, duplicate) {
            if (false) {
                console.log("Duplicate site: " + duplicate);

            } else { 
                   //console.log("Adding " + name)
                let site = new Site()
                site.name = name
                site.meta = {}
                site.group = group
                site.country = country
                site.geomix = []
                site.addedBy = req.user._id
                site.addedAt = Date.now()
                site.saveAsync().then(function(response){
                    tools.saveHistory(req, res, response._id, response.name, "Website Meta fetched.");
                    tools.saveHistory(req, res, response._id, response.name, "Link added for the first time."); //Save in history 
                    resolve(site);
                }).catch(function (e){
                    console.log(name);
                    reject();
                });  
            }
         });

    }else{
        console.log('Wrong Format');
    }
}).then((data) => {
      console.log('All websites processed!');
      addedSites.push(data);
}).catch(err => {
      //console.error('Failed');
}));

    res.send({ status: 'ok', message: ''});

Я делаю ajax-вызовы, поэтому возвращаю res.send({status: 'ok', message: ''}), я знаю, что это не то место, и я хочу отправить некоторые данные по res.send. В настоящее время он отправляет заголовки до фактического завершения кода. Я хочу отправить заголовки после того, как все данные будут добавлены в Mongo, но для каждого из них в этом случае он разрешает (), поэтому, если я отправлю заголовки внутри «.then» из «.each», я получу уже отправленные заголовки с ошибкой .

Это может немного сбивать с толку. Я чувствую, что делаю это неправильно. Я немного схожу с ума и не могу найти подходящий пример, который я могу понять и реализовать.

Но, в конце концов, мой главный вопрос: используя вызов Ajax, как правильно добавить, скажем, 1000 записей в коллекцию с использованием промисов и фактически правильно контролировать тех, кто не добавляет, и тех, кто этого не делает?

Прямо сейчас мой код действительно работает, но логика точно неверна.

Спасибо.


person DanielPanic    schedule 31.05.2017    source источник
comment
Избегайте антишаблона конструктора Promise конструктора! Если вам нужно промисифицировать Site.findOne, сделайте это в отдельной функции (или просто позвольте Bluebird сделать это за вас).   -  person Bergi    schedule 31.05.2017


Ответы (2)


Вы можете использовать bulkWrite на своей модели.

Ссылка: http://mongoosejs.com/docs/api.html#model_Model.bulkWrite< /а>

ИЗМЕНИТЬ:

Извините, я неправильно вас понял. Вам нужно переместить res.send({ status: 'ok', message: ''}); в блоки then() и catch(), так что вы получите что-то вроде этого:

Promise.each(sites, sites => new Promise((resolve, reject) => {
    // stuff you did before
}).then((data) => {
    console.log('All websites processed!');
    addedSites.push(data);
    res.send({ status: 'ok', message: ''});
}).catch(err => {
    res.send({ status: 'failed', message: err.message});
}));
person ponury-kostek    schedule 31.05.2017
comment
Не уверен, что это полезно. Я знаю об этой функции, и я мог бы ее использовать. Я все еще запутался, и моя цель состоит в том, чтобы понять, как правильно выполнять обещания и обрабатывать ошибки. Даже если я реализую bulkWrite, у меня все равно будет та же проблема. - person DanielPanic; 31.05.2017
comment
Это лучше, но я все же пришел к такому выводу. Но проверяйте это каждый раз, когда я сохраняю, у меня есть разрешение(), поэтому он отправляет этот заголовок каждый раз и до того, как код действительно сработает (в моем случае во внешнем интерфейсе я использую status.ok, и я также отправляю предупреждение пользователю, я заполняю дом с данными), если я помещу туда res.send. Я исправил это, подсчитав размер добавляемых записей и получив приращение, когда они оба совпадают. Я отправляю заголовок. Не уверен, что это самый элегантный способ сделать - person DanielPanic; 31.05.2017

Это то, что я тоже пришел, если кто-то может мне сказать, хорошая ли это арка.

    exports.addBulkSite = function(req, res, next) {
    let siteArray = csv.parse((req.body.sites).trim()),
        addedSites = [],
        failedSites = [],
        duplicated = [],
        sites = siteArray,
        size = sites.length,
        processed = 0,
        meta;
    Promise.each(sites, sites => new Promise((resolve, reject) => {
        let name = tools.extractDomain(req, res, sites[0]),
            country = sites[1],
            group = sites[2];
        if (name != "" && country != "" && group != "") {
            Site.findOneAsync({ name: name }, "_id").then(function(duplicate) {
                duplicated.push(duplicate);
                reject({name:name, message: 'Duplicated', critical:false});         
             }).catch(function(notDuplicated){
                let site = new Site()
                site = { 
                            name: name, 
                            meta: {}, 
                            group: group, 
                            country: country, geomix:{}, 
                            addedBy: req.user._id,
                            addedAt:Date.now()
                        }
                site.saveAsync().then(function(response){
                    tools.saveHistory(req, res, response._id, response.name, "Website Meta fetched.");
                    tools.saveHistory(req, res, response._id, response.name, "Link added for the first time."); //Save in history 
                    resolve(site);
                }).catch(function (e){
                    console.log(e);
                    reject({name:name, message: 'Error saving in the database. Please contact the administrator.', critical: true});
                });  
            });
        }else{
            reject({name:name, message: 'Paramaters are missing', critical:false});
        }
    }).then((data) => {
          processed++;
          addedSites.push(data);
          if(processed==size){
            console.log('out');
            res.send({ status: 'ok', addedSites: addedSites, failedSites: failedSites, duplicated: duplicated});
          }
    }).catch((err) => {
          processed++;
          console.log(err);
          failedSites.push(err);
          if(processed==size){
            console.log('out');
            res.send({ status: 'ok', addedSites: addedSites, failedSites: failedSites, duplicated: duplicated});
          }
    })); 
}
person DanielPanic    schedule 31.05.2017
comment
Когда вы все равно используете findOneAsync, избегайте Promise антипаттерн конструктора! - person Bergi; 31.05.2017
comment
Я читаю кое-что об этом, но, поскольку я новичок в обещаниях, мне трудно понять, и я поместил это в свой код, и мне бы очень хотелось, чтобы вы могли объяснить это лучше, используя мой код, который дал бы мне больше перспективы. Все еще проводите некоторые исследования, и ваш совет уже действительно полезен, поскольку он означает, что это правильное направление. Спасибо. - person DanielPanic; 31.05.2017
comment
Просто удалите часть new Promise((resolve, reject) => { и вместо этого добавьте return к каждой функции, возвращая значение или обещание (или throw для отказа). - person Bergi; 31.05.2017
comment
Постараюсь понять, весь день убивал себя и немного запутался. Не уверен, как это реализовать сразу, но этот совет и предоставленная вами ссылка помогут, и вам просто нужно поспать над этим: P Спасибо, приятель. - person DanielPanic; 31.05.2017