2017-02-10 6 views
3

おそらく私は完全な約束やSequalizeを理解していないかもしれませんが、しばらくしてから非同期DB操作がより単純な場合にのみうまくいくと感じています。 同期DBアクセスを求める質問の数によって、私だけではないようです。Node.js Sequelizeでファイルからデータベースを挿入

私の場合です。化合物を含むCSVファイルがあるとします。各行には、化合物に関する情報とセミコロンで区切られた成分のリストが格納されています。そして、そこからIngredientテーブルを作成したいのですが、重複はありません。例えば

、ファイルが行

C1インガが含まれている場合は、IngB

C2インガ; IngC

は、我々は3つのレコード、インガ、IngB、およびIngCで成分表をしたいです。 したがって、行が読み込まれると、各成分チェックがすでに存在する場合はそれを追加しない場合は、化合物を保存する必要があります。コードは次のとおりです。

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がテーブルに2回挿入されることです。私の推測では、Sequelizeメソッドは、約束を返し、ファイルから行を読み込む方がDB挿入が高速です。したがって、最初の行のIngAは、新しい行が読み込まれ、IngAが見つかったときにまだ挿入されていません。

私はいくつかのアプローチを試しましたが、すべてがこの種のタスクには複雑すぎるようです。さらに重要なことは、動作しません。

+1

ステップでそれを行うのはどうですか?配列内のすべての値を読み込み、重複を削除し、 'bulkCreate'操作を実行します。 – piotrbienias

+0

正確に私が現在やっていること:)しかし、それはファイル全体を2回通過する必要があり、処理はストリーミングされません - CSVファイルは400Kのラインを持つことができるので、Big Setオブジェクトをメモリに保持します。希望オプションは、これは一般的なデータ入力タスクです。 –

答えて

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の助けを借りて、次の約束を実行する前に約束が完了するまで待つことになります。

関連する問題