マングースのユニークなインデックスが機能していません!


95

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

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

同じメールで2人のユーザーを救うことができます。くそー。

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

今のところ、ユーザーを見つけるために手動でdbを呼び出しています。「電子メール」は索引付けされているため、この呼び出しは高額ではありません。しかし、それでもネイティブに処理できるようにするとよいでしょう。

誰かがこれに対する解決策を持っていますか?


1
悪いニュースですが、mongod v2.4.3、mongoose v3.6.20にはまだ問題があります
damphat

一意は私のホストの1つで機能しているようですが、別のホストでまったく同じノード/マングースコードを使用して一意を強制できません。正しく動作するホストは単一のmongod3.4.10を実行し、そうでないホストはmongod 3.2.17で設定されたレプリカを実行します。両方のホストでコレクションを最初から作成しているため、既存の重複は問題になりません。私はこのページのほとんどの解決策を試しましたが、うまくいったのは@IsaacPakのmongoose-unique-validatorでした。
Maksym

回答:


95

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


4
同じ問題が発生していますが、OSXでmongoを再起動する方法がわかりません。プロセスを強制終了すると、プロセスは自動的に再び生成され、一意のインデックスはまだ機能しません...何かアイデアはありますか?
ragulka 2012

7
「おっと、mongoを再起動する必要がある」とはどういう意味ですか?!データベースを停止せずにインデックスを追加することは不可能だと言っていますか?
andrewrk 2013

7
これは真実ではありません。インデックスを追加するためにmongoを再起動する必要はありません。
JohnnyHK 2014

1
ユニークなことのために..私はmongoを再起動しなければなりませんでした..そしてそれはうまくいきました..ありがとう!
ムハマドアフサンアヤズ2015

2
再起動してみました。また、インデックスを再作成します。これを解決するには、データベースを削除する必要がありました。問題を推測すると、インデックスを追加する前に重複がすでに存在していたため、本番データベースでは重複を削除してから再起動する必要がありますか?
isimmons 2015年

40

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

また、次のようにインデックスを再作成します。

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

テストでは、重要なデータがないため、次のこともできます。

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

16
db.dropDatabase()はデータベースをワイプします!
アイザックパック

28

同じ問題が発生しました。データベースにユーザーを追加した後、emailフィールドに一意の制約を追加しましたUserSchemaが、重複した電子メールでユーザーを保存することができました。私は次のようにしてこれを解決しました:

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

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

ステップ1に関して、Mongoのドキュメントから次のことに注意してください。

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

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


11

この動作は、Mongoに重複を残した場合にも発生します。Mongooseは、アプリケーションの起動時にMongoでそれらを作成しようとします。

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

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

10

わかりました。フィールドにインデックスを追加し、一意のプロパティを設定することで、mongoshellからこれを解決できました。

db.<collectionName>.ensureIndex({fieldName: 1}, {unique: true});

シェルは次のように応答する必要があります。

{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

モンゴシェルからすばやくテストします。

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: { : \"martyna@martycud.com\" }"
    }
})

10

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

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()コードの実行中に次の非推奨の警告が表示されていたbcという行を追加しました。

(node:21553) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.

Foo.createIndexes()非同期かどうかはわかりませんが、AFAIKは正常に機能しているようです


問題を中心に展開するのではなく、問題に対処する質問に対する唯一の答え。
SakshamGupta19年

この答えは私を助けました。私が見逃していたのindex: trueは、独自のインデックスを作成することだけでした。
elcid

6

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

コレクションではなくドロップインデックスと書かれています
Zero0Ho

5

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

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

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


5
後半相手にビットが、何が良い「ユニークなインデックスを強制する際に少し緩い」だORMである
Imre_G

何の役にも立たないコメントを軽蔑するのは何が良いことでしょう。このソリューションは堅実で、本番環境に対応しています。
アイザックパック

4

次のいずれかの場合、Mongooseはサイレントに一意のインデックスの追加に失敗します。

  1. コレクションにはすでに同じ名前のインデックスがあります
  2. コレクションには、インデックス付きフィールドの重複を含むドキュメントがすでに含まれています

最初のケースでは、インデックスを。でリストしdb.collection.getIndexes()、古いインデックスをdb.collection.dropIndex("index_name")。で削除します。Mongooseアプリケーションを再起動すると、新しいインデックスが正しく追加されます。

2番目のケースでは、Mongooseアプリケーションを再起動する前に、重複を削除する必要があります。


3

マングース-ユニーク-バリデーター

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

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: 'old-email@example.com' },
      { email: 'new-email@example.com' },
      { 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に挿入することができます。

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

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


2

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


1

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

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

db.users.dropIndex('username_1');


1

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

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

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

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

ここでmongoDBを再起動します。


1

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


1

私はしばらく同じ問題に直面し、多くの検索を行いました、そして私にとっての解決策はcreateIndexes()機能でした。

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

したがって、コードはそのようになります。

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

0

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

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

それを削除してみてください。それでも問題が解決しない場合は、このスレッドで提案されているように、mongodb再起動してみてください。


0

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

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

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

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

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

db.User.drop()

0

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

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

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

  7. セーブ

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


ここでのオブジェクト{"email":1}の1の意味は何ですか?
siluveru kiran kumar

0

一意のインデックスを付けたばかりのフィールドの冗長性がコレクションにないことを確認してください。

次に、アプリを再起動します(マングース)。サイレントにインデックスを追加するだけで失敗します。


0

コレクションからすべてのドキュメントを削除する:

db.users.remove({})

そして、他の人が言ったように、再起動は私のために働いた


0

あなたのMongoDBは、(あなたが端子を介してmongod.exeファイルを起動せずにデータベースに接続する必要がない場合は、これを見つける簡単な方法がある)サービスとして動作している場合は、その変更を行った後、あなたは、サービスを再起動する必要がある場合がありますおよび/または、データベースを完全に削除します。

一部のユーザーにとっては、1つのコレクションをドロップするだけで機能するため、これは非常に奇妙です。それらのいくつかは、データベースを削除する必要がありました。しかし、それらは私にとってはうまくいきませんでした。データベースを削除してから、MongoDBサーバーサービスを再起動しました。

Windows検索バーでサービス検索サービスを再開してからMongoDBサービスを見つけるには、ダブルクリックして開き、停止してサービスを再開します。

他の方法がうまくいかなかった場合は、これでうまくいくと思います。


0

私の場合、マングースは時代遅れでした。CMDで古いnpmを実行して確認しました。そして「マングース」を更新しました。

それがあなたにもうまくいったかどうか教えてください。


どのバージョンを使用していましたか?
baboo_

0

データベースをアプリケーションに接続するときに、次のオプションを追加します。「audoIndex:true」たとえば、私のコードでは次のようにしました。

const options = {
// your options go here
...
// this code is the solution
audoIndex: true
}
mongoose.connect(DB_URI, options);

また、問題のあるコレクションを削除し、それが機能することを確認するために再作成しました。https://dev.to/emmysteven/solved-mongoose-unique-index-not-working-45d5でこのソリューションを見つけまし た。「RestartMongoDB」などのソリューションも試しましたが、うまくいきませんでした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.