복붙노트

[MONGODB] 키 필드에 의해 MongoDB의 컬렉션에서 모든 중복 문서를 찾기

MONGODB

키 필드에 의해 MongoDB의 컬렉션에서 모든 중복 문서를 찾기

나는 문서의 일부 세트 컬렉션을 가지고 가정하자. 이 같은.

{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":1, "name" : "foo"}
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":2, "name" : "bar"}
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":3, "name" : "baz"}
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":4, "name" : "foo"}
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":5, "name" : "bar"}
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":6, "name" : "bar"}

나는 "이름"필드에 의해이 컬렉션의 모든 중복 항목을 찾고 싶어요. 예를 들면 "푸"두 번 표시하고 "바"3 번 나타납니다.

해결법

  1. ==============================

    1.참고 :이 솔루션은 이해하기 쉬운, 그러나 최고입니다.

    참고 :이 솔루션은 이해하기 쉬운, 그러나 최고입니다.

    당신은 문서가 특정 필드가 몇 번 찾아 맵리 듀스를 사용할 수 있습니다 :

    var map = function(){
       if(this.name) {
            emit(this.name, 1);
       }
    }
    
    var reduce = function(key, values){
        return Array.sum(values);
    }
    
    var res = db.collection.mapReduce(map, reduce, {out:{ inline : 1}});
    db[res.result].find({value: {$gt: 1}}).sort({value: -1});
    
  2. ==============================

    2.허용 대답은 대형 컬렉션에 정말 느린이며, 중복 레코드의 _ids를 반환하지 않습니다.

    허용 대답은 대형 컬렉션에 정말 느린이며, 중복 레코드의 _ids를 반환하지 않습니다.

    집계는 훨씬 더 빨리하고 _ids을 반환 할 수 있습니다 :

    db.collection.aggregate([
      { $group: {
        _id: { name: "$name" },   // replace `name` here twice
        uniqueIds: { $addToSet: "$_id" },
        count: { $sum: 1 } 
      } }, 
      { $match: { 
        count: { $gte: 2 } 
      } },
      { $sort : { count : -1} },
      { $limit : 10 }
    ]);
    

    집계 파이프 라인의 첫 번째 단계에서, $ 그룹 uniqueIds 연산자 집합체의 이름 필드가 문서 저장 그룹화 된 각 레코드 _id 값. 하여 $ 합 조작이 경우, 일정한 1 전달 된 필드의 값을 가산 - 이에 카운트 필드로 분류 레코드의 개수를 카운트.

    파이프 라인의 두 번째 단계에서, 우리는 $ 일치를 사용 적어도 2의 카운트, 즉 중복 필터와 문서.

    그런 다음 우리는 종류의 가장 흔한 첫 번째 중복, 그리고 상위 10에 결과를 제한 할 수 있습니다.

    자신의 _ids과 함께 중복 된 이름을 가진 $ 한계 기록이 쿼리가 출력해서. 예를 들면 :

    {
      "_id" : {
        "name" : "Toothpick"
    },
      "uniqueIds" : [
        "xzuzJd2qatfJCSvkN",
        "9bpewBsKbrGBQexv4",
        "fi3Gscg9M64BQdArv",
      ],
      "count" : 3
    },
    {
      "_id" : {
        "name" : "Broom"
      },
      "uniqueIds" : [
        "3vwny3YEj2qBsmmhA",
        "gJeWGcuX6Wk69oFYD"
      ],
      "count" : 2
    }
    
  3. ==============================

    3.일반적인 몽고 솔루션의 경우, 그룹을 사용하여 중복을 찾기위한 MongoDB의 요리 책의 레시피를 참조하십시오. 이 집계는보다 빠르고 강력한에서는 중복 레코드의 _ids를 반환 할 수 있다는 것입니다 있습니다.

    일반적인 몽고 솔루션의 경우, 그룹을 사용하여 중복을 찾기위한 MongoDB의 요리 책의 레시피를 참조하십시오. 이 집계는보다 빠르고 강력한에서는 중복 레코드의 _ids를 반환 할 수 있다는 것입니다 있습니다.

    pymongo의 경우, 허용 대답은 (맵리 듀스를 사용하여)이 효율적이지 않습니다. 대신, 우리는 그룹 방법을 사용할 수 있습니다 :

    $connection = 'mongodb://localhost:27017';
    $con        = new Mongo($connection); // mongo db connection
    
    $db         = $con->test; // database 
    $collection = $db->prb; // table
    
    $keys       = array("name" => 1); Select name field, group by it
    
    // set intial values
    $initial    = array("count" => 0);
    
    // JavaScript function to perform
    $reduce     = "function (obj, prev) { prev.count++; }";
    
    $g          = $collection->group($keys, $initial, $reduce);
    
    echo "<pre>";
    print_r($g);
    

    출력이 될 것입니다 :

    Array
    (
        [retval] => Array
            (
                [0] => Array
                    (
                        [name] => 
                        [count] => 1
                    )
    
                [1] => Array
                    (
                        [name] => MongoDB
                        [count] => 2
                    )
    
            )
    
        [count] => 3
        [keys] => 2
        [ok] => 1
    )
    

    동등한 SQL 쿼리는 다음과 같습니다 이름으로 PRB 그룹에서 SELECT 이름, COUNT (이름). 우리는 여전히 배열에서 0의 수와 요소를 필터링 할 필요가 있습니다. 다시 말하지만, 그룹을 사용하여 표준 솔루션 그룹을 사용하여 중복을 찾기위한 MongoDB의 요리 책 레시피를 참조하십시오.

  4. ==============================

    4.나는 공식 몽고 랩 블로그에 유용한 정보를 발견 : http://blog.mongolab.com/2014/03/finding-duplicate-keys-with-the-mongodb-aggregation-framework/

    나는 공식 몽고 랩 블로그에 유용한 정보를 발견 : http://blog.mongolab.com/2014/03/finding-duplicate-keys-with-the-mongodb-aggregation-framework/

  5. ==============================

    5.여기에 가장 높은 허용 대답이있다 :

    여기에 가장 높은 허용 대답이있다 :

    uniqueIds: { $addToSet: "$_id" },
    

    그것은 또한 ID의 목록을 당신에게 uniqueIds라는 새 필드를 반환합니다. 하지만 당신은 단지 필드의 수를 어떻게해야할까요? 그 다음이 될 것입니다 :

    db.collection.aggregate([ 
      {$group: { _id: {name: "$name"}, 
                 count: {$sum: 1} } }, 
      {$match: { count: {"$gt": 1} } } 
    ]);
    

    당신은 MySQL과 PostgreSQL을 같은 SQL 데이터베이스에서 오는 경우이를 설명하기 위해, 당신은 집계 함수에 익숙한 (예를 들어, COUNT (), SUM (), MIN (), MAX는 ()) 문 BY 그룹과 함께하는 일을 위해, 당신을 허용 예를 들어, 열 값은 표에 나타나는 총 카운트를 검색한다.

    SELECT COUNT(*), my_type FROM table GROUP BY my_type;
    +----------+-----------------+
    | COUNT(*) | my_type         |
    +----------+-----------------+
    |        3 | Contact         |
    |        1 | Practice        |
    |        1 | Prospect        |
    |        1 | Task            |
    +----------+-----------------+
    

    당신이 볼 수 있듯이, 우리의 출력을 보여줍니다 카운트 각 my_type 값이 나타납니다. MongoDB의 중복 항목을 찾으려면, 우리는 유사한 방법으로 문제를 해결한다. MongoDB를 자랑은 복수의 문서로부터 연산 그룹 값을 집계하고 단일 결과를 반환하기 위해 그룹화 된 데이터에 다양한 작업을 수행 할 수있다. 그것은 SQL의 집계 함수와 유사한 개념이다.

    모음라는 연락처, 다음과 같이 초기 설정 외모를 가정 :

    db.contacts.aggregate([ ... ]);
    

    이 집계 함수는 집계 사업자의 배열을, 우리의 목표는 필드의 수, 필드 값의 차례 나오는 수만큼 데이터가 그룹이기 때문에 우리의 경우, 우리는 $ 그룹 연산자를 원한다.

    db.contacts.aggregate([  
        {$group: { 
            _id: {name: "$name"} 
            } 
        }
    ]);
    

    이 방법에 약간의 idiosyncracy이있다. _id 필드는 오퍼레이터에 의해 그룹을 사용하는 것이 요구된다. 이 경우, 우리는 $ 이름 필드를 그룹화하고 있습니다. _id 내에서 키 이름은 어떤 이름을 가질 수 있습니다. 그것은 여기에 직관적이기 때문에 그러나 우리는 이름을 사용합니다.

    (가 컬렉션에 한 번 이상 한 번 이상 나타나면 관계없이)에만 $ 그룹 연산자를 사용하여 집계를 실행하여, 우리는 이름 필드의 목록을 얻을 것이다 :

    db.contacts.aggregate([  
      {$group: { 
        _id: {name: "$name"} 
        } 
      }
    ]);
    
    { "_id" : { "name" : "John" } }
    { "_id" : { "name" : "Joan" } }
    { "_id" : { "name" : "Stephen" } }
    { "_id" : { "name" : "Rod" } }
    { "_id" : { "name" : "Albert" } }
    { "_id" : { "name" : "Amanda" } }
    

    집계가 어떻게 작동하는지 위의주의 사항. 그것은 이름 필드 문서를했다 추출 이름 필드의 새 컬렉션을 반환합니다.

    하지만 우리가 알고 싶은 것은 많은 시간이 필드 값 다시 표시하지 방법이다. 하여 $ 그룹 운영자는 그룹 내의 각 문서의 총 식 1을 추가 $ 합 연산자를 사용하여 카운트 필드 걸린다. 는 $ 그룹 그래서 및 $ 합 함께 모든 숫자 값의 집단 합계를 반환 주어진 필드 (예 : 이름)에 대한 결과입니다.

    db.contacts.aggregate([  
      {$group: { 
        _id: {name: "$name"},
        count: {$sum: 1}
        } 
      }
    ]);
    
    { "_id" : { "name" : "John" },  "count" : 1  }
    { "_id" : { "name" : "Joan" },  "count" : 3  }
    { "_id" : { "name" : "Stephen" },  "count" : 2 }
    { "_id" : { "name" : "Rod" },  "count" : 3 }
    { "_id" : { "name" : "Albert" },  "count" : 2 }
    { "_id" : { "name" : "Amanda" },  "count" : 1 }
    

    목표는 중복을 제거하는 것이었다 때문에, 하나의 추가 단계가 필요합니다. 하나 이상의 수를에만 그룹을 얻으려면, 우리는 우리의 결과를 필터링 할 $ 일치 연산자를 사용할 수 있습니다. 은 $ 일치 연산자 내에서, 우리는 카운트 필드를 확인하고 "이상"과 숫자 1을 나타내는 $ GT는 연산자를 사용하여 하나 이상의 계수를 찾기 위해 그에게 그것을 말할 것이다.

    db.contacts.aggregate([ 
      {$group: { _id: {name: "$name"}, 
                 count: {$sum: 1} } }, 
      {$match: { count: {"$gt": 1} } } 
    ]);
    
    { "_id" : { "name" : "Joan" },  "count" : 3  }
    { "_id" : { "name" : "Stephen" },  "count" : 2 }
    { "_id" : { "name" : "Rod" },  "count" : 3 }
    { "_id" : { "name" : "Albert" },  "count" : 2 }
    

    루비에 대한 Mongoid 같은 ORM을 통해 MongoDB를 사용하는 경우 보조 노트로서,이 오류를 얻을 수 있습니다 :

    The 'cursor' option is required, except for aggregate with the explain argument 
    

    이 가능성이 가장 높은 수단 당신의 ORM은 오래되어 그 MongoDB를 더 이상 지원하지 않는 작업을 수행하고 있습니다. 따라서, 중 당신의 ORM을 업데이트하거나 수정 프로그램을 찾을 수 있습니다. Mongoid, 이것은 나를 위해 수정했다 :

    module Moped
      class Collection
        # Mongo 3.6 requires a `cursor` option be passed as part of aggregate queries.  This overrides
        # `Moped::Collection#aggregate` to include a cursor, which is not provided by Moped otherwise.
        #
        # Per the [MongoDB documentation](https://docs.mongodb.com/manual/reference/command/aggregate/):
        #
        #   Changed in version 3.6: MongoDB 3.6 removes the use of `aggregate` command *without* the `cursor` option unless
        #   the command includes the `explain` option. Unless you include the `explain` option, you must specify the
        #   `cursor` option.
        #
        #   To indicate a cursor with the default batch size, specify `cursor: {}`.
        #
        #   To indicate a cursor with a non-default batch size, use `cursor: { batchSize: <num> }`.
        #
        def aggregate(*pipeline)
          # Ordering of keys apparently matters to Mongo -- `aggregate` has to come before `cursor` here.
          extract_result(session.command(aggregate: name, pipeline: pipeline.flatten, cursor: {}))
        end
    
        private
    
        def extract_result(response)
          response.key?("cursor") ? response["cursor"]["firstBatch"] : response["result"]
        end
      end
    end
    
  6. from https://stackoverflow.com/questions/9491920/find-all-duplicate-documents-in-a-mongodb-collection-by-a-key-field by cc-by-sa and MIT license