programing

MongoDB: 배열 요소의 속성에 대한 고유 인덱스

starjava 2023. 7. 6. 21:44
반응형

MongoDB: 배열 요소의 속성에 대한 고유 인덱스

이와 유사한 구조를 가지고 있습니다.

class Cat {
  int id;
  List<Kitten> kittens;
}

class Kitten {
  int id;
}

사용자가 동일한 ID의 고양이를 둘 이상 사용하여 고양이를 만들지 못하도록 합니다.다음과 같이 인덱스를 만들어 보았습니다.

db.Cats.ensureIndex({'id': 1, 'kittens.id': 1}, {unique:true})

하지만 제가 잘못된 형식의 고양이를 삽입하려고 하면, Mongo는 그것을 받아들입니다.

제가 뭔가를 놓쳤나요? 이게 가능할까요?

고유 인덱스는 서로 다른 문서에 고유성만 적용하므로 중복 키 오류가 발생할 수 있습니다.

db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )

그러나 이는 허용됩니다.

db.cats.insert( { id: 123, kittens: [ { id: 456 }, { id: 456 } ] } )

Mongo 레벨에서 당신이 필요로 하는 제약을 적용할 방법이 있는지 모르겠습니다, 혹시 업데이트를 삽입할 때 애플리케이션 로직에서 확인할 수 있는 것이 아닐까요?

배열 필드에서 개별 값의 고유성 보장

위의 예 외에도 MongoDB에는 배열 필드에 새 개체/값을 추가할 때 값/객체가 아직 존재하지 않는 경우에만 업데이트를 수행하도록 하는 기능이 있습니다.

따라서 다음과 같은 문서가 있으면 다음과 같습니다.

{ _id: 123, kittens: [456] }

이는 허용됩니다.

db.cats.update({_id:123}, {$push: {kittens:456}})

결과적으로

{ _id: 123, kittens: [456, 456] }

그러나 $addToSet 함수($push가 아닌)를 사용하면 값을 추가하기 전에 값이 이미 있는지 확인합니다.그럼, 다음과 같이 시작합니다.

{ _id: 123, kittens: [456] }

실행 중:

db.cats.update({_id:123}, {$addToSet: {kittens:456}})

아무 효과도 없을 것입니다.

따라서, 긴 이야기의 짧고 고유한 제약 조건은 배열 필드의 값 항목 내에서 고유성을 검증하지 않습니다. 단지 두 문서가 색인 필드에서 동일한 값을 가질 수 없다는 것입니다.

배열 특성에 고유한 삽입이 있습니다.다음 명령은 기본적으로 아기 고양이의 고유성을 보장하는 동시에 삽입합니다(123이 있는 개체가 아직 존재하지 않는 경우 업퍼트가 사용자를 위해 작성됨).

db.cats.update(
  { id: 123 },
  { $addToSet: {kittens: { $each: [ 456, 456] }}, $set: {'otherfields': 'extraval', "field2": "value2"}},
  { upsert: true}
)

객체의 결과 값은 다음과 같습니다.

{
    "id": 123,
    "kittens": [456],
    "otherfields": "extraval",
    "field2": "value2"
}

여기서 중요한 것은 mongodb 개체 배열에 동일한 ID 또는 고유하게 처리해야 하는 일부 다른 필드를 가진 항목만 존재하지 않도록 하는 것입니다.그런 다음, 이와 같은 간단한 쿼리는 다음을 사용하여 업데이트하기에 충분합니다.$addToSet.

죄송합니다. 저는 자바 몽고 드라이버 버전 4.0.3을 사용하는 몽고 셸 전문가가 아닙니다.

collection = database.getCollection("cat", Cat.class);
UpdateResult result = collection.updateOne(and(eq("Id", 1), nin("kittens.id", newKittenId)), addToSet("kittens", new Kitten("newKittenId")));

여기에 사용된 쿼리는 일치 쿼리에 추가 조건을 추가했습니다. 여기서 cat.id 은 1이고 새 KittenId는 아직 이전에 추가된 고양이가 소유하지 않습니다.따라서 고양이의 ID가 발견되었지만 새 고양이 ID를 가져간 고양이가 없으면 쿼리가 진행되고 새 고양이를 추가하여 고양이의 고양이를 업데이트합니다.그러나 새로운 KittenId가 고양이 중 한 마리에 의해 찍혔다면, 그것은 단순히 업데이트 결과를 카운트 없이 반환하고 수정된 필드는 반환하지 않습니다(아무 일도 일어나지 않습니다).

참고: 이것은 kitten.id 의 고유 제약 조건을 보장하지 않으며, mongo DB는 문서의 객체 배열에 대한 고유성을 지원하지 않으며, addToSet은 객체 배열에서 중복된 항목을 실제로 처리하지 않습니다. 단, 객체가 데이터베이스에 있는 내용의 100% 복제본인 경우는 제외합니다.addToSet.

문서 검증기를 사용하여 수행할 수 있는 해결 방법이 있습니다.

다음은 "a"가 배열이고 "a" 하위 문서 필드 "b" 값이 고유해야 하는 검증자의 예입니다.이렇게 하면 컬렉션이 비어 있거나 이미 규칙을 준수하는 것으로 가정합니다.

> db.runCommand({collMod:"coll", validator: {$expr:{$eq:[{$size:"$a.b"},{$size:{$setUnion:"$a.b"}}]}}})
/* test it */
> db.coll.insert({a:[{b:1}]}) /* success */
> db.coll.update({},{ '$push' : { 'a':{b:1}}})
WriteResult({
    "nMatched" : 0,
    "nUpserted" : 0,
    "nModified" : 0,
    "writeError" : {
        "code" : 121,
        "errmsg" : "Document failed validation"
    }
})

원본 게시물에서 이 솔루션에 대한 자세한 정보 보기

이 경우 사용자 지정 Mongoose 유효성 검사 방법을 작성할 수 있습니다.사후 검증에 연결할 수 있습니다.Mongoose에는 유효성 검사가 있으며 유효성 검사 전(사전) 또는 후(사후)에 후크를 구현할 수 있습니다.이 경우 사후 검증을 사용하여 어레이가 유효한지 확인할 수 있습니다.그런 다음 배열에 중복이 없는지 확인하십시오.세부 정보에 따라 효율성을 개선할 수 있습니다.예를 들어 '_id'만 있으면 JS include 함수를 사용할 수 있습니다.

catSchema.post('validate',function(next) {
    return new Promise((resolve,reject) => {
        for(var i = 0; i < this.kittens.length; i++) {
           let kitten = this.kittens[i];
           for(var p = 0; p < this.kittens.length; p++) {
              if (p == i) {
                  continue;
              }
              if (kitten._id == this.kittens[p]._id) {
                  return reject('Duplicate Kitten Ids not allowed');
              }
           }
        }
        return resolve();
    });
});

저는 오류를 지정하는 것이 더 쉽기 때문에 검증에 약속을 사용하는 것을 좋아합니다.

언급URL : https://stackoverflow.com/questions/6743849/mongodb-unique-index-on-array-elements-property

반응형