Express.js - массив данных foreach и сохранение их в базе данных

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

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

Вот код:

router.post('/save/', function(req, res){
    var data = req.body;
    var result = [];
    for (var i in data) {
        var d = data[i];
        if (d.user_id == -1) d.user_id = null;
        new Term().where({'date_of_driving': d.day})
        .fetch()
        .then(function(terms){
            if (terms != null) {
                return new Term({'id':terms.id}).save(d).then(function(item_updated){});
            } else {
                return new Term().save(d).then(function(item_saved){});               
           }
        })
        .catch(function(error){
            console.log(error);
        });
    }
    res.send({'saved': 'ok'});   
});

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

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


person uglycode    schedule 04.03.2015    source источник
comment
Этот вопрос и ответ может помочь вам понять вашу проблему.   -  person Rodrigo Medeiros    schedule 04.03.2015
comment
в этой строке: return new Term({'id':term.id}).save(d).then(function(item_updated){}); term не определено, а d не ссылается на то, на что вы хотите ссылаться. Использование foreach, предложенное в вашем заголовке, решит эту проблему, если request.body является массивом.   -  person Kevin B    schedule 04.03.2015
comment
Кевин Б. спасибо за ответ: это опечатка, я перевел код на английский, а это там потерялось. Я отредактировал код сейчас. Я не совсем понимаю вторую часть вашего ответа - я использую предложение for. Насколько я знаю, в javascript на самом деле нет foreach. Или есть?   -  person uglycode    schedule 04.03.2015


Ответы (2)


Из вашего кода неясно, хотите ли вы, чтобы запросы выполнялись параллельно или последовательно.

Я предполагаю параллель, но вы можете заменить .map на .each, и он будет работать последовательно.

router.post('/save/', function(req, res){
    Promise.map(req.body, function(d) {
        if (d.user_id == -1) d.user_id = null;
        return new Term().where({'date_of_driving': d.day}).fetch().then(function(terms){
            if (terms != null) {
                return new Term({'id':terms.id}).save(d);
            } else {
                return new Term().save(d);    
            }
        });
    }).then(function() {
        res.send({'saved': 'ok'});
    }).catch(Promise.OperationalError, function(e) {
        // Note that stack reveals internal server code so you might
        // not want to send it over in production
        res.status(400).send({stack: e.stack, message: e.message});
    });
});

Нет необходимости ловить ошибку только для ее регистрации, поэтому я удалил ее. Ловите ошибку только тогда, когда вы можете с ней справиться.

person Esailija    schedule 05.03.2015

По сути, функция «тогда» будет выполняться асинхронно, а цикл продолжит свое выполнение независимо, как вы и подозревали.

Я считаю, что одно из решений состоит в том, чтобы определить функцию, которая по существу будет принимать параметр d в качестве ссылки и выполнять с ним асинхронные действия. Итак, это должно работать:

router.post('/save/', function(req, res){
    var data = req.body;
    var result = [];
    for (var i in data) {
        var d = data[i];
        if (d.user_id == -1) d.user_id = null;
        doTheThing(d);
    }
    res.send({'saved': 'ok'});   
});


function doTheThing(d) {
    new Term().where({'date_of_driving': d.day})
        .fetch()
        .then(function(terms){
            if (terms != null) {
                return new Term({'id':terms.id}).save(d).then(function(item_updated){});
            } else {
                return new Term().save(d).then(function(item_saved){});               
            }
        })
    .catch(function(error){
        console.log(error);
    });
}
person Kalle Björklid    schedule 04.03.2015
comment
Как насчет использования Promise. карта? Предполагается, что они решают такие вопросы? - person uglycode; 05.03.2015
comment
@uglycode Я немного новичок в программировании узлов/обещаний, поэтому я не знаю ответа на этот вопрос (мне также было бы интересно узнать об элегантных решениях). Я мог бы изучить это (я имел в виду полностью изучить API Bluebird), но тем временем я добавил теги «bluebird» и «обещание» к вашему сообщению (не видны до рецензирования), так что давайте посмотрим, может ли кто-то еще может вступать в общий разговор. - person Kalle Björklid; 05.03.2015