web-dev-qa-db-ja.com

Mongooseユニークインデックスが機能しない!

MongoDBにインデックスに基づいて重複する値を検出させようとしています。 MongoDBではこれが可能だと思いますが、Mongooseラッパーを使用すると、問題が発生するようです。そのため、次のようになります。

User = new Schema ({
  email: {type: String, index: {unique: true, dropDups: true}}
})

同じメールで2人のユーザーを保存できます。くそー.

同じ問題がここに表明されています: https://github.com/LearnBoost/mongoose/issues/56 、しかしそのスレッドは古く、どこにもありません。

今のところ、ユーザーを見つけるためにdbを手動で呼び出しています。 「email」にはインデックスが付けられているため、この呼び出しは高価ではありません。しかし、それをネイティブに処理できるようにすることはまだ素晴らしいことです。

誰にもこれに対する解決策がありますか?

72
foobar

おっとっと! mongoを再起動するだけです。

77
foobar

おっとっと! mongoを再起動するだけです。

そして、再インデックスも!

テストでは、私はちょうどやった:

mongo <db-name>
> db.dropDatabase()

ただし、重要なデータがそこにある場合は、おそらく次のことが必要です。

mongo <db-name>
> db.<collection-name>.reIndex()
39
jpillora

私は同じ問題にぶつかりました:既にユーザーをデータベースに追加した後、emailフィールドの一意の制約をUserSchemaに追加しましたが、それでもユーザーをだましメールで保存できました。私は次のことを行ってこれを解決しました:

1)usersコレクションからすべてのドキュメントを削除します。

2)mongoシェルから、コマンドdb.users.createIndex({email: 1}, {unique: true})を実行します

ステップ1に関して、Mongoのドキュメントから:

MongoDBは、コレクションにインデックスの一意制約に違反するデータが既に含まれている場合、指定されたインデックスフィールドに一意のインデックスを作成できません。

https://docs.mongodb.com/manual/core/index-unique/

19
Neil Strain

この動作は、Mongoに重複が残っている場合にも発生します。 Mongooseは、アプリケーションの起動時にMongoで作成しようとします。

これを防ぐには、このエラーを次のように処理できます。

yourModel.on('index', function(err) {
  if (err?) {
    console.error err
  }
);
11
Pierre Maoui

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]\" }"
    }
})
9
sigman.pl

アプリケーションレベルから一意のインデックスを適用する場合、Mongooseは少し緩いです。したがって、mongo cliを使用してデータベース自体から一意のインデックスを適用するか、UserSchemaの直後に次のコード行を記述してuniqueインデックスについて真剣であることを明示的にmongooseに通知することをお勧めします。

UserSchema.index({ username: 1, email: 1 }, { unique: true});

これにより、UserSchemaのusernameフィールドとemailフィールドの両方に一意のインデックスが適用されます。乾杯。

5
moeabdol

ドキュメントによると: 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})
4
Damien Romito

私はこのようなことをしました:

_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()が非同期かどうかはわかりませんが、知る限りではうまく機能しているようです

4
solstice333

mongoose-unique-validator

このプラグインの使用方法:

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)追加オプション

  1. 大文字小文字を区別しません

    スキーマでuniqueCaseInsensitiveオプションを使用します

    _ie. email: { type: String, index: true, unique: true, required: true, uniqueCaseInsensitive: true }_

  2. カスタムエラーメッセージ

    ie. exampleSchema.plugin(uniqueValidator, { message: 'Error, expected {PATH} to be unique.' });

これで、mongoの再起動、データベースの削除、インデックスの作成を心配することなく、スキーマに一意のプロパティを追加/削除できます。

警告(ドキュメントから):

非同期操作に依存してドキュメントがデータベースに存在するかどうかを確認するため、2つのクエリを同時に実行し、両方を0に戻し、両方をMongoDBに挿入することができます。

コレクションを自動的にロックするか、単一の接続を強制する以外には、実際の解決策はありません。

ほとんどのユーザーにとって、これは問題にはなりませんが、注意すべきEdgeのケースです。

3
Isaac Pak

スキーマのautoIndexがtrueであることを確認します。mongoose.connectオプションを使用する場合は、false(デフォルトはtrue)に設定される可能性があります。

1
Lee Quinze

テーブル/コレクションが空の場合、フィールドの一意のインデックスを作成します。

db.<collection_name>.createIndex({'field':1}, {unique: true})

テーブル/コレクションが空でない場合は、コレクションを削除してインデックスを作成します。

db.<collection_name>.drop()
db.<collection_name>.createIndex({'field':1}, {unique: true})

次に、mongoDBを再起動します。

1
Rakin Afser

インデックスを削除することでもこの問題を解決できます。

コレクションusersおよびフィールドusernameから一意のインデックスを削除する場合、次のように入力します。

db.users.dropIndex('username_1');

1

最新の回答:mongodbを再起動する必要はありません。collecitonに同じ名前のインデックスが既にある場合、mongooseはインデックスを再作成しないため、collecitonの既存のインデックスを最初に削除します。 、上記のプロセスで問題が解決しました。

1
chen Jacky

次のような接続方法でオプション_autoIndex: false_を使用している場合:

mongoose.connect(CONNECTION_STRING, { autoIndex: false });

削除してみてください。それでもうまくいかない場合は、このスレッドで提案されている多くのremonting mongodbを試してください。

0
Rafael Mejía

スキーマを次のように定義できます

User = new Schema ({
  email: {
      type: String,
      unique: true
  }
})

ただし、既にドキュメントが存在し、その後ユーザーのスキーマを変更した場合、これは機能しない可能性があります。コレクションを削除したくない場合は、このユーザーコレクションのメールにインデックスを作成できます。このコマンドを使用して、電子メールのインデックスを作成できます。

db.User.createIndex({email:1},{unique: true})

または、コレクションをドロップして、ユーザーを再度追加することもできます。
コレクションを削除するには、次を入力できます。

db.User.drop()
0
Pulkit Aggarwal

私はしばらくの間同じ問題に直面し、多くの検索を行いましたが、解決策はcreateIndexes()関数でした。

それがお役に立てば幸いです。

コードは次のようになります。

User = new Schema ({
   email: {type: String, unique: true}
});
User.createIndexes();
0
Samir Hosny

この問題が発生したときに、データベースを削除し、サーバー(nodemon)を何度も再起動しようとしましたが、どのトリックもまったく機能しませんでした。 Robo 3Tを使用して、次の回避策を見つけました。

  1. Robo 3Tで、データベースをダブルクリックしてコレクションを開きます
  2. コレクションを開いて、問題のコレクションを表示します。まず、コレクションが空であることを確認してください
  3. インデックスフォルダを右クリックします。デフォルトでは、_id_がデフォルトです。ここで、インデックスの追加を選択します
  4. 名前を選択します。たとえば、電子メールフィールドにはemailと入力します
  5. キーをJSONとして提供します。例えば

    {
       "email": 1
    }
    
  6. 一意のチェックボックスをクリックします

  7. セーブ

これにより、重複する電子メールがMongoDBに保存されないようになります。

0
Balepur