developer tip

몽구스 고유 색인이 작동하지 않습니다!

copycodes 2020. 10. 23. 08:01
반응형

몽구스 고유 색인이 작동하지 않습니다!


MongoDB가 인덱스를 기반으로 중복 값을 감지하도록하려고합니다. 나는 이것이 MongoDB에서 가능하다고 생각하지만 Mongoose 래퍼를 통해 모든 것이 깨진 것처럼 보입니다. 그래서 다음과 같이 :

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

동일한 이메일로 2 명의 사용자를 저장할 수 있습니다. 꿰매다.

https://github.com/LearnBoost/mongoose/issues/56 에서 동일한 문제가 표현 되었지만 해당 스레드는 오래되어 아무데도 없습니다.

지금은 사용자를 찾기 위해 수동으로 db를 호출하고 있습니다. 이 호출은 "이메일"이 인덱싱되므로 비용이 많이 들지 않습니다. 그러나 기본적으로 처리되도록하는 것이 여전히 좋습니다.

누구든지 이것에 대한 해결책이 있습니까?


이런! mongo를 다시 시작하면됩니다.


이런! mongo를 다시 시작하면됩니다.

또한 다음을 사용하여 다시 색인화합니다.

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

테스트에서 중요한 데이터가 없기 때문에 다음을 수행 할 수도 있습니다.

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

같은 문제에 부딪 혔습니다. 이미 db에 사용자를 추가 한 후 email필드에 대한 고유 한 제약 조건을 추가했으며 UserSchema여전히 중복 이메일로 사용자를 저장할 수있었습니다. 다음을 수행하여이 문제를 해결했습니다.

1) 사용자 컬렉션에서 모든 문서를 제거합니다.

2) mongo 셸에서 다음 명령을 실행합니다. db.users.createIndex({email: 1}, {unique: true})

1 단계와 관련하여 Mongo의 문서에서 다음 사항에 유의하십시오.

MongoDB는 컬렉션에 인덱스에 대한 고유 제약 조건을 위반하는 데이터가 이미 포함되어있는 경우 지정된 인덱스 필드에 고유 인덱스를 만들 수 없습니다.

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


이 동작은 Mongo에 일부 중복 항목을 남긴 경우에도 발생합니다. Mongoose는 애플리케이션이 시작될 때 Mongo에서 생성을 시도합니다.

이를 방지하려면 다음과 같이이 오류를 처리 할 수 ​​있습니다.

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

좋아, 필드에 인덱스를 추가하고 고유 속성을 설정하여 mongoshell에서이 문제를 해결할 수있었습니다.

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

Shell은 다음과 같이 응답해야합니다.

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

Mongoose는 응용 프로그램 수준에서 고유 한 인덱스를 적용 할 때 약간 느슨합니다. 따라서 mongo cli를 사용하여 데이터베이스 자체에서 고유 인덱스를 적용하거나 uniqueUserSchema 바로 뒤에 다음 코드 줄을 작성하여 mongoose에게 인덱스에 대해 진지함을 명시 적으로 알리는 것이 좋습니다.

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

이렇게하면 UserSchema의 usernameemail필드 모두에 고유 인덱스가 적용됩니다 . 건배.


문서에 따르면 : 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()코드가 실행될 때 다음과 같은 사용 중단 경고가 표시되는 bc 줄을 추가 했습니다.

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

Foo.createIndexes()비동기 인지 확실하지 않지만 AFAIK가 제대로 작동하는 것 같습니다.


몽구스 고유 유효성 검사기

이 플러그인을 사용하는 방법 :

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.' });

Now you can add/delete the unique property to your schemas without worrying about restarting mongo, dropping databases, or creating indexes.

Caveats (from the docs):

Because we rely on async operations to verify whether a document exists in the database, it's possible for two queries to execute at the same time, both get 0 back, and then both insert into MongoDB.

Outside of automatically locking the collection or forcing a single connection, there's no real solution.

For most of our users this won't be a problem, but is an edge case to be aware of.


You can also resolve this issue by dropping the index;

let's assume you want to remove the unique index from collection users and field username, type this:

db.users.dropIndex('username_1');


If the table/collection is empty, then create unique index for the field:

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

If the table/collection is not empty, then drop the collection and create index:

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

Now restart mongoDB.


Newest answer: there is no need to restart mongodb at all, if colleciton has same name indexes already, mongoose will not recreate your indexes again, so, drop colleciton's existing indexes firstly, and now, when you run mongoose, it will create new index, above process solved my problem.


check that autoIndex in the schema is true, it maybe set false(default true) when you use mongoose.connect options


If you are using the option autoIndex: false in the connection method like this:

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

Try removing that. If that doesn't work, try restarting mongodb as many suggested in this thread.


You can define your schema as

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

But maybe this will not work when there is already a document and after that, you have changed the schema of the User. You can create an index on email for this User collection if you don't want to drop the collection. Using this command you can create an index on email.

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

Or you can just drop the collection and add the user again.
For Dropping the collection, you can enter this:

db.User.drop()

I faced the same issue for awhile and did a lot of searching and the solution for me was the createIndexes() function.

I wish that helps.

so the code will be like that.

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

When I encountered this problem, I tried dropping the database, re-starting the server (nodemon) many times and none of the tricks didn't work at all. I found the following work around, through Robo 3T:

  1. In the Robo 3T, double click on the Database to open the collections
  2. Open the collections to reveal the Collection in question. Make sure your collections are empty, to begin with
  3. Right-click on the Indexes Folder. By default, you will see the _id_ as the default. Now, choose Add Index
  4. Choose a name, say email for e-mail field, for example
  5. Provide Keys as JSON. For example

    {
       "email": 1
    }
    
  6. Click on the Unique checkbox

  7. Save

This will make sure no duplicate emails are saved in the MongoDB.

참고URL : https://stackoverflow.com/questions/5535610/mongoose-unique-index-not-working

반응형