MongoDBにインデックスに基づいて重複する値を検出させようとしています。 MongoDBではこれが可能だと思いますが、Mongooseラッパーを使用すると、問題が発生するようです。そのため、次のようになります。
User = new Schema ({
email: {type: String, index: {unique: true, dropDups: true}}
})
同じメールで2人のユーザーを保存できます。くそー.
同じ問題がここに表明されています: https://github.com/LearnBoost/mongoose/issues/56 、しかしそのスレッドは古く、どこにもありません。
今のところ、ユーザーを見つけるためにdbを手動で呼び出しています。 「email」にはインデックスが付けられているため、この呼び出しは高価ではありません。しかし、それをネイティブに処理できるようにすることはまだ素晴らしいことです。
誰にもこれに対する解決策がありますか?
おっとっと! mongoを再起動するだけです。
おっとっと! mongoを再起動するだけです。
そして、再インデックスも!
テストでは、私はちょうどやった:
mongo <db-name>
> db.dropDatabase()
ただし、重要なデータがそこにある場合は、おそらく次のことが必要です。
mongo <db-name>
> db.<collection-name>.reIndex()
私は同じ問題にぶつかりました:既にユーザーをデータベースに追加した後、email
フィールドの一意の制約をUserSchema
に追加しましたが、それでもユーザーをだましメールで保存できました。私は次のことを行ってこれを解決しました:
1)usersコレクションからすべてのドキュメントを削除します。
2)mongoシェルから、コマンドdb.users.createIndex({email: 1}, {unique: true})
を実行します
ステップ1に関して、Mongoのドキュメントから:
MongoDBは、コレクションにインデックスの一意制約に違反するデータが既に含まれている場合、指定されたインデックスフィールドに一意のインデックスを作成できません。
この動作は、Mongoに重複が残っている場合にも発生します。 Mongooseは、アプリケーションの起動時にMongoで作成しようとします。
これを防ぐには、このエラーを次のように処理できます。
yourModel.on('index', function(err) {
if (err?) {
console.error err
}
);
OK、フィールドにインデックスを追加し、一意のプロパティを設定することで、mongoshellからこれを解決できました。
db.<collectionName>.ensureIndex({fieldName: 1}, {unique: true});
シェルは次のように応答する必要があります。
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
次に、mongoshellからすばやくテストします。
var doc = {fieldName: 'abc'};
db.<collectionName>.insert(doc)
与えるべき:WriteResult({"nInserted":1})
しかし、もう一度繰り返すと:
db.<collectionName>.insert(doc)
あげる:
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: fuelConsumption.users.$email_1 dup key: { : \"[email protected]\" }"
}
})
アプリケーションレベルから一意のインデックスを適用する場合、Mongooseは少し緩いです。したがって、mongo cliを使用してデータベース自体から一意のインデックスを適用するか、UserSchemaの直後に次のコード行を記述してunique
インデックスについて真剣であることを明示的にmongooseに通知することをお勧めします。
UserSchema.index({ username: 1, email: 1 }, { unique: true});
これにより、UserSchemaのusername
フィールドとemail
フィールドの両方に一意のインデックスが適用されます。乾杯。
ドキュメントによると: https://docs.mongodb.com/v2.6/tutorial/modify-an-index/
既存のインデックスを変更するには、インデックスを削除して再作成する必要があります。
MONGOを再起動しないでください!
1-コレクションをドロップします
db.users.drop()
2-テーブルのインデックスを再作成します
db.users.ensureIndex({email: 1, type: 1}, {unique: true})
私はこのようなことをしました:
_const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const FooSchema = new Schema({
name: { type: String, required: true, index: true, unique: true }
});
const Foo = mongoose.model('Foo', FooSchema);
Foo.createIndexes();
module.exports = Foo
_
Foo.createIndexes()
行b.cを追加しました。コードの実行中に次の非推奨警告が表示されました。
_(node:21553) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.
_
Foo.createIndexes()
が非同期かどうかはわかりませんが、知る限りではうまく機能しているようです
このプラグインの使用方法:
1)npm install --save mongoose-unique-validator
2)スキーマで次のガイドに従ってください:
_// declare this at the top
var mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');
// exampleSchema = mongoose.Schema({}) etc...
exampleSchema.plugin(uniqueValidator);
// module.exports = mongoose.model(...) etc....
_
3)マングース法
findOneAndUpdate
などのメソッドを使用する場合、この構成オブジェクトを渡す必要があります。
_{ runValidators: true, context: 'query' }
_
_ie. User.findOneAndUpdate(
{ email: '[email protected]' },
{ email: '[email protected]' },
{ runValidators: true, context: 'query' },
function(err) {
// ...
}
_
4)追加オプション
大文字小文字を区別しません
スキーマでuniqueCaseInsensitiveオプションを使用します
_ie. email: { type: String, index: true, unique: true, required: true, uniqueCaseInsensitive: true }
_
カスタムエラーメッセージ
ie. exampleSchema.plugin(uniqueValidator, { message: 'Error, expected {PATH} to be unique.' });
これで、mongoの再起動、データベースの削除、インデックスの作成を心配することなく、スキーマに一意のプロパティを追加/削除できます。
警告(ドキュメントから):
非同期操作に依存してドキュメントがデータベースに存在するかどうかを確認するため、2つのクエリを同時に実行し、両方を0に戻し、両方をMongoDBに挿入することができます。
コレクションを自動的にロックするか、単一の接続を強制する以外には、実際の解決策はありません。
ほとんどのユーザーにとって、これは問題にはなりませんが、注意すべきEdgeのケースです。
スキーマのautoIndexがtrueであることを確認します。mongoose.connectオプションを使用する場合は、false(デフォルトはtrue)に設定される可能性があります。
テーブル/コレクションが空の場合、フィールドの一意のインデックスを作成します。
db.<collection_name>.createIndex({'field':1}, {unique: true})
テーブル/コレクションが空でない場合は、コレクションを削除してインデックスを作成します。
db.<collection_name>.drop()
db.<collection_name>.createIndex({'field':1}, {unique: true})
次に、mongoDBを再起動します。
インデックスを削除することでもこの問題を解決できます。
コレクションusers
およびフィールドusername
から一意のインデックスを削除する場合、次のように入力します。
db.users.dropIndex('username_1');
最新の回答:mongodbを再起動する必要はありません。collecitonに同じ名前のインデックスが既にある場合、mongooseはインデックスを再作成しないため、collecitonの既存のインデックスを最初に削除します。 、上記のプロセスで問題が解決しました。
次のような接続方法でオプション_autoIndex: false
_を使用している場合:
mongoose.connect(CONNECTION_STRING, { autoIndex: false });
削除してみてください。それでもうまくいかない場合は、このスレッドで提案されている多くのremonting mongodbを試してください。
スキーマを次のように定義できます
User = new Schema ({
email: {
type: String,
unique: true
}
})
ただし、既にドキュメントが存在し、その後ユーザーのスキーマを変更した場合、これは機能しない可能性があります。コレクションを削除したくない場合は、このユーザーコレクションのメールにインデックスを作成できます。このコマンドを使用して、電子メールのインデックスを作成できます。
db.User.createIndex({email:1},{unique: true})
または、コレクションをドロップして、ユーザーを再度追加することもできます。
コレクションを削除するには、次を入力できます。
db.User.drop()
私はしばらくの間同じ問題に直面し、多くの検索を行いましたが、解決策はcreateIndexes()
関数でした。
それがお役に立てば幸いです。
コードは次のようになります。
User = new Schema ({
email: {type: String, unique: true}
});
User.createIndexes();
この問題が発生したときに、データベースを削除し、サーバー(nodemon)を何度も再起動しようとしましたが、どのトリックもまったく機能しませんでした。 Robo 3Tを使用して、次の回避策を見つけました。
_id_
がデフォルトです。ここで、インデックスの追加を選択しますemail
と入力しますキーをJSONとして提供します。例えば
{
"email": 1
}
一意のチェックボックスをクリックします
これにより、重複する電子メールがMongoDBに保存されないようになります。