mongoose を使用して mongo データベースにデータを追加しようとしていますが、ほとんどのデータが既にデータベースにある可能性が高く、少数のフィールドのみを更新する必要があります。レコードの作成時刻と最終更新時刻を保存する必要があります。
この問題を解決するための最初の試みには、Model.save 関数の使用が含まれていました。これは、モデルがサーバーと呼ばれ、データが外部の http サービスからのオブジェクトであり、データで一意の _id を指定していることを前提としています。
var instance = new Server(data);
instance.save(function(err){
if(err)
console.log(err);
});
また、私の事前保存フック:
ServerSchema.pre('save', function(next) {
this.lastseen = Date.now();
if (!this.isNew)
return next() //if the entry isn't new, lets not change the date registred
this.registered = Date.now();
next() //Don't forget this!
})
ここでの問題は、重複した _id で保存がチョークし、エラーが発生することです。E11000 duplicate key error index...
これは、ドキュメントinstance
が new 演算子を使用して作成されていない場合にのみ保存が更新されるため、意味があります。
そのため、次の試みでは、ドキュメントを検索するコードを追加し、underscore.js を使用_.extend
して新しいドキュメントをデータベースで見つかったドキュメントとマージし、それをデータベースに保存しました。このアプローチの問題点は、処理されるデータのチャンクごとにデータベースへの追加の呼び出しが必要になることです。
私の 3 回目の試みでは、データベースにデータを保存するという点で、これを使用して動作しますが、スキーマはデフォルトであり、Model.findByIdAndUpdate
フックはトリガーされません。{upsert:true}
pre-save
4 回目の試行では、この要旨で @aheckmann によって提案されたコードを使用します: https://gist.github.com/2764948
var server = new Server();
server.init(ping);
server.save(function(err){
if(err) {
console.log("DB Error: ",err);
return res.send('DB Error')
}
//if server approved, tell the inworld server to sync textures
if(server.approved)
res.send('success')
else
res.send('skip')
user.servers.addToSet(ping._id); //add the server to the user's list
user.save(function(err, usr){
if(err)
console.log("DB Error: ", err);
})
})
ここでも、pre-save
フックはトリガーされません。フックでアップサートする唯一の方法は、最初に findById でドキュメントを見つけようとすることだと理解する必要がありますか?
Q:
データのチャンクごとに複数のデータベース呼び出しを行うことなく、一意の主キーに基づいて挿入または更新を「アップサート」する方法はありますか? 私が見落としている方法、または明らかな事実はありますか?