1

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:

データのチャンクごとに複数のデータベース呼び出しを行うことなく、一意の主キーに基づいて挿入または更新を「アップサート」する方法はありますか? 私が見落としている方法、または明らかな事実はありますか?

4

1 に答える 1

4

mongoose の部分を削除して mongo ドライバーを直接使用しない限り、DB への 2 回未満の呼び出しでは実行できないと思います。ただし、静的メソッドを作成して、すべての作業を行うことができます。

ServerSchema.statics.findOrCreate(function(doc, next) {
  this.findById(doc._id, function(err, res) {
    res || (res = new this);
    _.extend(res, doc); // add new data to the document
    next(err, res); // if (err != null) then something went wrong
  });
});

findByIdAndUpdatemongo ドライバーを直接呼び出すため、presave フックをトリガーしません。

于 2013-01-03T11:38:11.000 に答える