2017-02-10 7 views
3

Возможно, я не понимаю полностью обещания или Sequalize, но после некоторого времени работы с ним возникает ощущение, что операции async DB работают хорошо только для более простых случаев. И по количеству вопросов, запрашивающих синхронный доступ к БД, это выглядит я не единственный.Вставка базы данных Node.js из файла с Sequelize

Это мое дело. Предположим, что у нас есть файл CSV с соединениями, где каждая строка содержит информацию о соединении, а также список ингредиентов, разделенных точкой с запятой. И мы хотим заполнить таблицу Ингредиентов, но без дублирования.

Например, если файл содержит строки

C1 Inga; IngB

C2 Inga; НИЛПСБ

Мы хотим Ингредиент таблицу с тремя записями, Inga, IngB и НИЛПСБ. Поэтому, когда строка считывается, она должна сохранять составную часть, поскольку каждый ингредиент проверяет, существует ли он, и если он не добавляется. Вот код:

var lineReader=require('readline').createInterface({ 
    input: require('fs').createReadStream(filename) 
}); 

lineReader.on('line', function(line) { 

let parts=line.split('\t'); 
compoundModel.create({ 
    name: parts[0], 
}).then(entity => { 
    let ingredients=parts[1].split(';'); 

    ingredients.forEach((ing, index) => { 
    ingModel.findOne({ 
     where: {name: ing} 
    }).then(ingEntity => { 
     if (ingEntity) { 
     return ingEntity; 
     } 
     return ingModel.create({ 
     name: ing 
     }) 
    }); 
    }).then(ingEntity => { 
    //something else 
    }); 
}); 
});  

Проблема в том, что IngA дважды вставлен в таблицу. Я предполагаю, что поиск или создание методов Sequelize возвращает обещания, а чтение строк из файла происходит быстрее, чем вставка БД. Поэтому IngA из первой строки еще не вставлен, когда читается новая строка и пытается найти IngA.

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

+1

Как сделать это шагами? Прочитайте все значения в массиве, удалите дубликаты и выполните операцию 'bulkCreate'. – piotrbienias

+0

Точно то, что я сейчас делаю :). Но он нуждается в двух проходах через весь файл, а обработка не транслируется - содержит большой объект Set в памяти, поскольку файл CSV может иметь 400K строк. Надеюсь, что есть лучший вариант, это обычная задача ввода данных. –

ответ

1

Вам необходимо выполнить транзакцию с блокировкой.

Выполните блокировку на уровне таблицы, чтобы предотвратить фантомные чтения происходит в вашем случае

http://docs.sequelizejs.com/en/v3/api/transaction/

+0

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

1

Пожалуйста оштрафовать ниже решения, он должен работать.

var await = require('asyncawait/await'); 

var lineReader=require('readline').createInterface({ 
    input: require('fs').createReadStream(filename) 
}); 

lineReader.on('line', function(line) { 

let parts=line.split('\t'); 
compoundModel.create({ 
    name: parts[0], 
}).then(entity => { 
    let ingredients=parts[1].split(';'); 

    ingredients.forEach((ing, index) => { 
     await(ingModel.findOrCreate({ 
      where: {name: ing}, defaults: {name: ing}, 
     }).spread(function(_record, _created){ 
     //Do something if required. _create will return true in case of entry already exists 
     })) 
    }).then(ingEntity => { 
    //something else 
    }); 
}); 
});  

Перед выполнением этого делать npm install asyncawait. С помощью await он будет ждать, пока обещание не завершит его выполнение до выполнения следующего обещания.

 Смежные вопросы

  • Нет связанных вопросов^_^