おめでとうございます。バグを発見したようです。これは、私のテストではMongoDB 3.0.0でのみ発生するか、少なくともMongoDB2.6.6には存在しません。バグがSERVER-17599で記録されるようになりました
注 :実際には「問題」ではありませんが、「設計上」確認されています。バージョン3.0.0のオプションを削除しました。ただし、まだドキュメントに記載されています。
問題は、インデックスが作成されておらず、「複合キー」フィールドに既存の重複があるコレクションでこれを作成しようとするとエラーが発生することです。上記では、インデックスを作成すると、シェルでこれが生成されます。
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"errmsg" : "exception: E11000 duplicate key error dup key: { : 15.0, : 1.0 }",
"code" : 11000,
"ok" : 0
}
重複が存在しない場合は、現在試行しているとおりにインデックスを作成でき、作成されます。
したがって、これを回避するには、最初に次のような手順で重複を削除します。
db.events.aggregate([
{ "$group": {
"_id": { "uid": "$uid", "sid": "$sid" },
"dups": { "$push": "$_id" },
"count": { "$sum": 1 }
}},
{ "$match": { "count": { "$gt": 1 } }}
]).forEach(function(doc) {
doc.dups.shift();
db.events.remove({ "_id": {"$in": doc.dups }});
});
db.events.createIndex({"uid":1 , "sid": 1},{unique:true})
その後、重複データを含むそれ以上の挿入は挿入されず、適切なエラーが記録されます。
ここでの最後の注意点は、「dropDups」は重複データを削除するための非常に洗練されたソリューションではないということです。上に示したように、もっと制御できるものが本当に必要です。
2番目の部分では、.insert()
を使用するのではなく .update()
を使用します 方法。 「アップサート」オプションがあります
$collection->update(
array( "uid" => 1, "sid" => 1 ),
array( '$set' => $someData ),
array( 'upsert' => true )
);
したがって、「見つかった」ドキュメントは「変更」され、見つからなかったドキュメントは「挿入」されます。 $setOnInsert
も参照してください ドキュメントが実際に挿入されたときにのみ特定のデータを作成し、変更されたときには作成しない方法。
特定の試みについては、.update()
の正しい構文 3つの引数です。 「クエリ」、「更新」、「オプション」:
$collection->update(
array( "uid" => 1, "sid" => 1 ),
array(
'$set' => array( "field" => "this" ),
'$inc' => array( "counter" => 1 ),
'$setOnInsert' => array( "newField" => "another" )
),
array( "upsert" => true )
);
どの更新操作も、その「更新」ドキュメントセクションの別の更新操作で使用される「同じパスにアクセス」することはできません。