ここにもう少し機能を追加して(非常にアドバイス)、変更されたドキュメントを返す必要がない場合は更新のオーバーヘッドを制限することに「気を配る」場合、または返す場合でも、アトミック演算子を使用することをお勧めします $ push
のような配列を使用
および $ addToSet
。
「追加機能」には、ストレージで配列を使用する場合、アイテムの「長さ」または「数」を格納することが非常に賢明な方法であるという点もあります。これはクエリで役立ち、配列の「カウント」を取得したり、フィルタリングの目的でその「カウント/長さ」を使用したりする他の方法とは対照的に、「インデックス」を使用して効率的にアクセスできます。
ここでのより良い構成は、"Bulk"操作 を使用することです。 存在する配列要素のテストは「アップサート」の概念とうまく混ざらないため、アップサート機能が必要な場合は、2つの操作で配列テストを行う方が適切です。ただし、「一括」操作は「1つの要求」でサーバーに送信でき、「1つの応答」も取得できるため、これにより、実際のオーバーヘッドが軽減されます。
var bulk = FollowModel.collection.initializeOrderedBulkOp();
// Try to add where not found in array
bulk.find({
"facebookId": req.user.facebookId,
"players": { "$ne": req.body.idToFollow }
}).updateOne({
"$push": { "players": req.body.idToFollow },
"$inc": { "playerCount": 1 }
});
// Otherwise create the document if not matched
bulk.find({
"facebookId": req.user.facebookId,
}).upsert().updateOne({
"$setOnInsert": {
"players": [req.body.idToFollow]
"playerCount": 1,
"fans": [],
"fanCount": 0
}
})
bulk.execute(function(err,result) {
// Handling in here
});
これが機能する方法は、追加する配列要素がまだ配列内に存在しないドキュメントを最初に見つけようとすることです。配列要素が存在しないためにドキュメントと一致しなかった唯一の理由である場合は、新しいドキュメントを作成したくないため、ここでは「アップサート」は試行されません。ただし、一致する場合は、新しいメンバーが配列に追加され、現在の「カウント」が $ inc
、合計数または長さを保持します。
したがって、2番目のステートメントはドキュメントのみに一致するため、「アップサート」を使用します。これは、キーフィールドにドキュメントが見つからない場合に作成されるためです。すべての操作は $ setOnInsert
>
その場合、ドキュメントがすでに存在する場合、操作は実行されません。
これはすべて実際には1つのサーバー要求と応答であるため、2つの更新操作を含めるための「前後」はなく、これにより効率的になります。
配列エントリの削除は基本的に逆ですが、今回は新しいドキュメントが見つからなかった場合に「作成」する必要がない点が異なります。
var bulk = FollowModel.collection.initializeOrderedBulkOp();
// Try to remove where found in array
bulk.find({
"facebookId": req.user.facebookId,
"players": req.body.idToFollow
}).updateOne({
"$pull": { "players": req.body.idToFollow },
"$inc": { "playerCount": -1 }
});
bulk.execute(function(err,result) {
// Handling in here
});
したがって、配列要素が存在する場所と、それがどこにあるかをテストするだけで済みます。 $ pull
削除を反映するために「カウント」を1ずつ「デクリメント」すると同時に、配列コンテンツから一致した要素。
これで、 $ addToSet
を「使用できます」 代わりに、ここでは配列の内容を確認し、メンバーが見つからない場合は追加されます。同じ理由で、 $pullを使用するときに存在する配列要素をテストする必要はありません。コード> 要素が存在しない場合は何もしません。さらに
$addToSet
そのコンテキストでは、MongoDBで同じパス上で複数の更新演算子を使用しようとすることが許可されていないため、「パスを越えて」いない限り、「アップサート」内で直接使用できます。
FollowModel.update(
{ "facebookId": req.user.facebookId },
{
"$setOnInsert": {
"fans": []
},
"$addToSet": { "players": req.body.idToFollow }
},
{ "upsert": true },
function(err,numAffected) {
// handling in here
}
);
しかし、これは「間違っている」でしょう:
FollowModel.update(
{ "facebookId": req.user.facebookId },
{
"$setOnInsert": {
"players": [], // <-- This is a conflict
"fans": []
},
"$addToSet": { "players": req.body.idToFollow }
},
{ "upsert": true },
function(err,numAffected) {
// handling in here
}
);
ただし、これを行うと、実際に何が存在するか、または何かが「追加」または「削除」されたかどうかに関係なく、そのような操作が完了しているだけなので、「カウント」機能が失われます。
「カウンター」を維持することは本当に良いことであり、現在すぐに使用していなくても、アプリケーションのライフサイクルのある段階で、おそらくそれらが必要になるでしょう。したがって、関連するロジックを理解し、それらを今すぐ実装することは非常に理にかなっています。後で多くの利益を得るために今すぐ支払う小さな価格。
可能な場合は一般的に「一括」操作をお勧めしますので、ここで簡単に説明します。 .collection
を介してこれを使用する場合 マングースのアクセサの場合、これらはネイティブドライバメソッドであるため、「マングース」メソッドとは動作が異なることに注意する必要があります。
特に、すべての「マングース」メソッドには、データベースへの接続が現在アクティブであることを確認するための組み込みの「チェック」があります。そうでない場合、接続が確立されるまで、操作は事実上「キューに入れられ」ます。ネイティブメソッドを使用すると、この「チェック」はなくなります。したがって、「最初に」実行された「mongoose」メソッドからの接続がすでに存在することを確認するか、接続が確立されるのを「待機」する構造でアプリケーションロジック全体をラップする必要があります。
mongoose.connection.on("open",function(err) {
// All app logic or start in here
});
そうすれば、接続が存在し、正しいオブジェクトが返され、メソッドで使用できることが確実になります。ただし、接続がなく、「一括」操作は失敗します。