컬렉션의 모든 키 이름 가져 오기


322

MongoDB 컬렉션의 모든 키 이름을 가져오고 싶습니다.

예를 들면 다음과 같습니다.

db.things.insert( { type : ['dog', 'cat'] } );
db.things.insert( { egg : ['cat'] } );
db.things.insert( { type : [] } );
db.things.insert( { hello : []  } );

고유 키를 얻고 싶습니다.

type, egg, hello

답변:


346

MapReduce로이를 수행 할 수 있습니다.

mr = db.runCommand({
  "mapreduce" : "my_collection",
  "map" : function() {
    for (var key in this) { emit(key, null); }
  },
  "reduce" : function(key, stuff) { return null; }, 
  "out": "my_collection" + "_keys"
})

그런 다음 결과 키에 대해 distinct를 실행하여 모든 키를 찾으십시오.

db[mr.result].distinct("_id")
["foo", "bar", "baz", "_id", ...]

2
안녕! 방금이 질문에 대한 후속 조치를 게시하여 데이터 구조 ( 스택 오버 플로우 .com / questions / 2997004 /…)의 더 깊은 레벨에있는 키로 도이 스 니펫을 작동시키는 방법을 묻습니다 .
Andrea Fiore

1
@kristina : 것들 컬렉션 에서 이것을 사용할 때 키로 나열된 모든 것을 어떻게 얻을 수 있습니까 ? 과거에 수정 한 것들을 얻었 기 때문에 이력 메커니즘과 관련이있는 것 같습니다 .
Shawn

3
나는 이것이 오래된 실이라는 것을 알고 있지만 비슷한 요구가있는 것 같습니다. nodejs mongodb 기본 드라이버를 사용하고 있습니다. 결과 임시 컬렉션은 항상 비어있는 것 같습니다. 이를 위해 컬렉션 클래스에서 mapreduce 함수를 사용하고 있습니다. 가능하지 않습니까?
Deepak

6
이것은 명백 할 수도 있지만, 하위 문서의 모든 고유 키 목록을 얻으려면 다음 줄을 수정하십시오.for (var key in this.first_level.second_level.nth_level) { emit(key, null); }
dtbarne

3
컬렉션에 저장 한 다음 별개로 실행하는 대신 map ()을 사용합니다.db.runCommand({..., out: { "inline" : 1 }}).results.map(function(i) { return i._id; });
Ian Stanley


74

당신은 새와 함께 집계를 사용할 수 있습니다 $objectToArrray에서 3.4.4다음 문서 배열에 모든 상위 키 및 값 쌍으로 변환 버전 $unwind$group $addToSet전체 컬렉션에서 개별의 키를 얻을 수 있습니다.

$$ROOT 최상위 문서를 참조하십시오.

db.things.aggregate([
  {"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
  {"$unwind":"$arrayofkeyvalue"},
  {"$group":{"_id":null,"allkeys":{"$addToSet":"$arrayofkeyvalue.k"}}}
])

단일 문서에서 키를 얻기 위해 아래 쿼리를 사용할 수 있습니다.

db.things.aggregate([
  {"$match":{_id: "5e8f968639bb8c67726686bc"}}, /* Replace with the document's ID */
  {"$project":{"arrayofkeyvalue":{"$objectToArray":"$$ROOT"}}},
  {"$project":{"keys":"$arrayofkeyvalue.k"}}
])

20
이것이 실제로 가장 좋은 대답입니다. 총 프레임 워크를 지원하는 모든 드라이버와 다른 프로그래밍 언어 또는 패키지 및 작품 관련이없는 해결 문제를 (심지어 유성을!)
미가 헤닝

2
"allkeys"키가있는 단일 맵 항목이 포함 된 커서가 아닌 배열을 반환하려는 경우 .next()["allkeys"]컬렉션에 요소가 하나 이상 있다고 가정하면 명령에 추가 할 수 있습니다 .
M. Justin

19

이 시도:

doc=db.thinks.findOne();
for (key in doc) print(key);

49
이것은 컬렉션의 단일 문서에 대한 필드 만 출력하므로 다른 답변은 완전히 다른 키를 가질 수 있습니다.
Asya Kamsky

15
그것은 여전히 ​​합리적인 합리적인 최소한 인 나에게 가장 유용한 답변입니다.
보리스 Burkov

11
유용하지 않습니까? 그것이 틀린 답을 줄 때 어떻게 유용합니까?
Zlatko 2016 년

4
상황에 따라 유용한 정보가 표시됩니다. 데이터가 정규화 된 경우 (예 : CSV 파일의 origen) 유용합니다 ... SQL에서 가져온 데이터의 경우 유용합니다.
피터 크라우스

5
그것은 좋은 대답이 아닙니다. 그것은 컬렉션의 모든 키가 아닌 컬렉션에서 요소의 키를 얻는 방법에 대한 답변 입니다!
yonatan

16

대상 컬렉션이 너무 크지 않으면 mongo shell client에서 시도해 볼 수 있습니다.

var allKeys = {};

db.YOURCOLLECTION.find().forEach(function(doc){Object.keys(doc).forEach(function(key){allKeys[key]=1})});

allKeys;

여기서보고 싶다면 특정 키에 대해 regExp를 제공하는 방법은 무엇입니까?
TB.M

@ TB.M 다음을 시도해보십시오. db.configs.find (). forEach (function (doc) {Object.keys (doc) .forEach (function (key) {if (/YOURREGEXP/.test(key)) { allKeys [key] = 1}})});
Li Chunlin

여기서 테스트는 무엇을 의미합니까? 설명해 주시겠습니까?
TB.M


14

pymongo를 사용하여 정리되고 재사용 가능한 솔루션 :

from pymongo import MongoClient
from bson import Code

def get_keys(db, collection):
    client = MongoClient()
    db = client[db]
    map = Code("function() { for (var key in this) { emit(key, null); } }")
    reduce = Code("function(key, stuff) { return null; }")
    result = db[collection].map_reduce(map, reduce, "myresults")
    return result.distinct('_id')

용법:

get_keys('dbname', 'collection')
>> ['key1', 'key2', ... ]

1
잘 작동합니다. 마침내 내 문제가 해결되었습니다. ... 이것은 스택 오버플로에서 본 가장 간단한 솔루션입니다.
Smack Alpha

유형별로 필터링하려면 예를 들어 if (typeof(this[key]) == 'number')before를 추가하십시오 emit(key, null).
Skippy le Grand Gourou

10

파이썬 사용하기. 컬렉션의 모든 최상위 키 집합을 반환합니다.

#Using pymongo and connection named 'db'

reduce(
    lambda all_keys, rec_keys: all_keys | set(rec_keys), 
    map(lambda d: d.keys(), db.things.find()), 
    set()
)

1
나는 이것이 효과가 있음을 발견했지만 원시 mongod 쿼리와 비교하여 얼마나 효율적입니까?
Jesus Gomez

1
나는 확실히이 MongoDB를 직접이 일에 비해 매우 비효율적이다 확신
잉고 피셔

9

다음은 Python에서 작동 한 샘플입니다.이 샘플은 결과를 인라인으로 반환합니다.

from pymongo import MongoClient
from bson.code import Code

mapper = Code("""
    function() {
                  for (var key in this) { emit(key, null); }
               }
""")
reducer = Code("""
    function(key, stuff) { return null; }
""")

distinctThingFields = db.things.map_reduce(mapper, reducer
    , out = {'inline' : 1}
    , full_response = True)
## do something with distinctThingFields['results']

9

mongodb 3.4.4 이상을 사용하는 경우 $objectToArray$group집계를 사용하여 아래 집계를 사용할 수 있습니다.

db.collection.aggregate([
  { "$project": {
    "data": { "$objectToArray": "$$ROOT" }
  }},
  { "$project": { "data": "$data.k" }},
  { "$unwind": "$data" },
  { "$group": {
    "_id": null,
    "keys": { "$addToSet": "$data" }
  }}
])

작업 는 다음과 같습니다.


이것이 가장 좋은 대답입니다. $match집계 파이프 라인의 시작 부분에서 조건과 일치하는 문서의 키만 가져올 수도 있습니다 .
RonquilloAeon

5

놀랍게도, 여기에 아무도 간단 javascript하고 Set논리를 사용 하여 중복 값을 자동으로 필터링하여 mongo 셸의 간단한 예를 아래에서 볼 수 있습니다.

var allKeys = new Set()
db.collectionName.find().forEach( function (o) {for (key in o ) allKeys.add(key)})
for(let key of allKeys) print(key)

컬렉션 이름에 가능한 모든 고유 를 인쇄합니다 : collectionName .


3

이것은 나를 위해 잘 작동합니다 :

var arrayOfFieldNames = [];

var items = db.NAMECOLLECTION.find();

while(items.hasNext()) {
  var item = items.next();
  for(var index in item) {
    arrayOfFieldNames[index] = index;
   }
}

for (var index in arrayOfFieldNames) {
  print(index);
}

3

여기 에 언급 된 것처럼이 작업을 수행하는 가장 좋은 방법은 mongod 3.4.4 이상이지만 $unwind연산자를 사용 하지 않고 파이프 라인에서 두 단계 만 사용 한다고 생각합니다 . 대신 $mergeObjectsand $objectToArray연산자를 사용할 수 있습니다 .

$group단계 에서는 $mergeObjects연산자를 사용 하여 컬렉션의 모든 문서에서 키 / 값이있는 단일 문서를 반환합니다.

그런 다음 $project우리가 사용 $map하고 $objectToArray키를 반환하는 곳 이옵니다.

let allTopLevelKeys =  [
    {
        "$group": {
            "_id": null,
            "array": {
                "$mergeObjects": "$$ROOT"
            }
        }
    },
    {
        "$project": {
            "keys": {
                "$map": {
                    "input": { "$objectToArray": "$array" },
                    "in": "$$this.k"
                }
            }
        }
    }
];

중첩 된 문서가 있고 키를 얻으려면이 작업을 수행 할 수 있습니다. 간단하게하기 위해 다음과 같은 간단한 포함 문서가있는 문서를 고려하십시오.

{field1: {field2: "abc"}, field3: "def"}
{field1: {field3: "abc"}, field4: "def"}

다음 파이프 라인은 모든 키 (field1, field2, field3, field4)를 생성합니다.

let allFistSecondLevelKeys = [
    {
        "$group": {
            "_id": null,
            "array": {
                "$mergeObjects": "$$ROOT"
            }
        }
    },
    {
        "$project": {
            "keys": {
                "$setUnion": [
                    {
                        "$map": {
                            "input": {
                                "$reduce": {
                                    "input": {
                                        "$map": {
                                            "input": {
                                                "$objectToArray": "$array"
                                            },
                                            "in": {
                                                "$cond": [
                                                    {
                                                        "$eq": [
                                                            {
                                                                "$type": "$$this.v"
                                                            },
                                                            "object"
                                                        ]
                                                    },
                                                    {
                                                        "$objectToArray": "$$this.v"
                                                    },
                                                    [
                                                        "$$this"
                                                    ]
                                                ]
                                            }
                                        }
                                    },
                                    "initialValue": [

                                    ],
                                    "in": {
                                        "$concatArrays": [
                                            "$$this",
                                            "$$value"
                                        ]
                                    }
                                }
                            },
                            "in": "$$this.k"
                        }
                    }
                ]
            }
        }
    }
]

약간의 노력으로 요소가 객체 인 배열 필드의 모든 하위 문서에 대한 키를 얻을 수 있습니다.


그렇습니다. $unwind수집 (필드 수 * 문서 수 없음)을 확장 $mergeObjects하면 모든 버전> 을 사용하여이를 피할 수 있습니다 3.6. -_-)
whoami

3

주제를 약간 벗어난 것일 수도 있지만 객체의 모든 키 / 필드를 재귀 적으로 인쇄 할 수 있습니다.

function _printFields(item, level) {
    if ((typeof item) != "object") {
        return
    }
    for (var index in item) {
        print(" ".repeat(level * 4) + index)
        if ((typeof item[index]) == "object") {
            _printFields(item[index], level + 1)
        }
    }
}

function printFields(item) {
    _printFields(item, 0)
}

컬렉션의 모든 객체가 동일한 구조를 가질 때 유용합니다.


1

모든 키 빼기의 목록을 얻으려면 _id다음 집계 파이프 라인을 실행하십시오.

var keys = db.collection.aggregate([
    { "$project": {
       "hashmaps": { "$objectToArray": "$$ROOT" } 
    } }, 
    { "$project": {
       "fields": "$hashmaps.k"
    } },
    { "$group": {
        "_id": null,
        "fields": { "$addToSet": "$fields" }
    } },
    { "$project": {
            "keys": {
                "$setDifference": [
                    {
                        "$reduce": {
                            "input": "$fields",
                            "initialValue": [],
                            "in": { "$setUnion" : ["$$value", "$$this"] }
                        }
                    },
                    ["_id"]
                ]
            }
        }
    }
]).toArray()[0]["keys"];

0

나는 nodejs로 쓰려고 노력했고 마침내 이것을 생각해 냈습니다.

db.collection('collectionName').mapReduce(
function() {
    for (var key in this) {
        emit(key, null);
    }
},
function(key, stuff) {
    return null;
}, {
    "out": "allFieldNames"
},
function(err, results) {
    var fields = db.collection('allFieldNames').distinct('_id');
    fields
        .then(function(data) {
            var finalData = {
                "status": "success",
                "fields": data
            };
            res.send(finalData);
            delteCollection(db, 'allFieldNames');
        })
        .catch(function(err) {
            res.send(err);
            delteCollection(db, 'allFieldNames');
        });
 });

새로 작성된 콜렉션 "allFieldNames"를 읽은 후 삭제하십시오.

db.collection("allFieldNames").remove({}, function (err,result) {
     db.close();
     return; 
});

0

mongoldb 문서 에 따라distinct

단일 컬렉션 또는 뷰에서 지정된 필드의 고유 한 값을 찾아 결과를 배열로 반환합니다.

인덱스의 수집 작업은 주어진 키 또는 인덱스에 대한 모든 가능한 값을 반환 무엇 :

컬렉션의 기존 인덱스를 식별하고 설명하는 문서 목록이 포함 된 배열을 반환합니다.

그래서 주어진 메소드에서 다음과 같은 메소드를 사용할 수 있습니다. 등록 된 모든 인덱스에 대해 컬렉션을 쿼리하고 키에 대한 인덱스가있는 객체를 반환하십시오 (이 예제는 NodeJS에 대해 async / await를 사용하지만 분명히 다른 비동기 방식을 사용할 수 있습니다).

async function GetFor(collection, index) {

    let currentIndexes;
    let indexNames = [];
    let final = {};
    let vals = [];

    try {
        currentIndexes = await collection.indexes();
        await ParseIndexes();
        //Check if a specific index was queried, otherwise, iterate for all existing indexes
        if (index && typeof index === "string") return await ParseFor(index, indexNames);
        await ParseDoc(indexNames);
        await Promise.all(vals);
        return final;
    } catch (e) {
        throw e;
    }

    function ParseIndexes() {
        return new Promise(function (result) {
            let err;
            for (let ind in currentIndexes) {
                let index = currentIndexes[ind];
                if (!index) {
                    err = "No Key For Index "+index; break;
                }
                let Name = Object.keys(index.key);
                if (Name.length === 0) {
                    err = "No Name For Index"; break;
                }
                indexNames.push(Name[0]);
            }
            return result(err ? Promise.reject(err) : Promise.resolve());
        })
    }

    async function ParseFor(index, inDoc) {
        if (inDoc.indexOf(index) === -1) throw "No Such Index In Collection";
        try {
            await DistinctFor(index);
            return final;
        } catch (e) {
            throw e
        }
    }
    function ParseDoc(doc) {
        return new Promise(function (result) {
            let err;
            for (let index in doc) {
                let key = doc[index];
                if (!key) {
                    err = "No Key For Index "+index; break;
                }
                vals.push(new Promise(function (pushed) {
                    DistinctFor(key)
                        .then(pushed)
                        .catch(function (err) {
                            return pushed(Promise.resolve());
                        })
                }))
            }
            return result(err ? Promise.reject(err) : Promise.resolve());
        })
    }

    async function DistinctFor(key) {
        if (!key) throw "Key Is Undefined";
        try {
            final[key] = await collection.distinct(key);
        } catch (e) {
            final[key] = 'failed';
            throw e;
        }
    }
}

따라서 기본 _id색인 으로 콜렉션을 조회 하면 다음을 리턴합니다 (테스트 콜렉션에는 테스트 시점에 하나의 문서 만 있음).

Mongo.MongoClient.connect(url, function (err, client) {
    assert.equal(null, err);

    let collection = client.db('my db').collection('the targeted collection');

    GetFor(collection, '_id')
        .then(function () {
            //returns
            // { _id: [ 5ae901e77e322342de1fb701 ] }
        })
        .catch(function (err) {
            //manage your error..
        })
});

NodeJS 드라이버 고유의 메소드를 사용합니다. 다른 답변이 제안했듯이 집계 프레임 워크와 같은 다른 접근법이 있습니다. 개인적 으로이 방법을보다 유연하게 찾을 수 있습니다. 결과를 반환하는 방법을 쉽게 만들고 미세 조정할 수 있습니다. 분명히 이것은 중첩 속성이 아닌 최상위 속성에만 적용됩니다. 또한 2 차 색인 (기본 _id 이외의 색인)이있는 경우 모든 문서가 표시되도록하려면 해당 색인을로 설정해야합니다 required.


0

mongo js 파일을 사용하여이를 달성 할 수 있습니다. getCollectionName.js 파일 에 아래 코드를 추가하고 아래 주어진 Linux 콘솔에서 js 파일을 실행하십시오.

mongo --host 192.168.1.135 getCollectionName.js

db_set = connect("192.168.1.135:27017/database_set_name"); // for Local testing
// db_set.auth("username_of_db", "password_of_db"); // if required

db_set.getMongo().setSlaveOk();

var collectionArray = db_set.getCollectionNames();

collectionArray.forEach(function(collectionName){

    if ( collectionName == 'system.indexes' || collectionName == 'system.profile' || collectionName == 'system.users' ) {
        return;
    }

    print("\nCollection Name = "+collectionName);
    print("All Fields :\n");

    var arrayOfFieldNames = []; 
    var items = db_set[collectionName].find();
    // var items = db_set[collectionName].find().sort({'_id':-1}).limit(100); // if you want fast & scan only last 100 records of each collection
    while(items.hasNext()) {
        var item = items.next(); 
        for(var index in item) {
            arrayOfFieldNames[index] = index;
        }
    }
    for (var index in arrayOfFieldNames) {
        print(index);
    }

});

quit();

감사합니다 @ackuser


0

@James Cropcho의 답변에 따라, 나는 사용하기 매우 쉬운 것으로 나타났습니다. 이 도구는 정확히 내가 찾고 있던 mongoeye 입니다.

이 도구를 사용하면 명령 줄에서 스키마를 내보내는 데 약 2 분이 걸렸습니다.


0

나는이 질문이 10 살이라는 것을 알고 있지만 C # 솔루션이 없으며 이것을 알아내는 데 몇 시간이 걸렸습니다. .NET 드라이버를 사용하고 System.Linq있으며 키 목록을 반환합니다.

var map = new BsonJavaScript("function() { for (var key in this) { emit(key, null); } }");
var reduce = new BsonJavaScript("function(key, stuff) { return null; }");
var options = new MapReduceOptions<BsonDocument, BsonDocument>();
var result = await collection.MapReduceAsync(map, reduce, options);
var list = result.ToEnumerable().Select(item => item["_id"].ToString());

-1

Carlos LM의 솔루션을 약간 확장하여 더 자세하게 설명했습니다.

스키마의 예 :

var schema = {
    _id: 123,
    id: 12,
    t: 'title',
    p: 4.5,
    ls: [{
            l: 'lemma',
            p: {
                pp: 8.9
            }
        },
         {
            l: 'lemma2',
            p: {
               pp: 8.3
           }
        }
    ]
};

콘솔에 입력하십시오.

var schemafy = function(schema, i, limit) {
    var i = (typeof i !== 'undefined') ? i : 1;
    var limit = (typeof limit !== 'undefined') ? limit : false;
    var type = '';
    var array = false;

    for (key in schema) {
        type = typeof schema[key];
        array = (schema[key] instanceof Array) ? true : false;

        if (type === 'object') {
            print(Array(i).join('    ') + key+' <'+((array) ? 'array' : type)+'>:');
            schemafy(schema[key], i+1, array);
        } else {
            print(Array(i).join('    ') + key+' <'+type+'>');
        }

        if (limit) {
            break;
        }
    }
}

운영:

schemafy(db.collection.findOne());

산출

_id <number>
id <number>
t <string>
p <number>
ls <object>:
    0 <object>:
    l <string>
    p <object>:
        pp <number> 

3
그의 대답은 틀렸고 당신은 그 위에 세워졌습니다. 요점은 모든 다음 문서와 다른 필드를 가질 수있는 첫 번째 문서가 아니라 모든 문서 의 모든 필드 를 출력 하는 것입니다.
Asya Kamsky

-3

1 간단한 해결 방법이 있습니다 ...

데이터 / 문서를 기본 컬렉션 "things"에 삽입하는 동안 1 개의 개별 컬렉션에 속성을 삽입해야 "things_attributes"라고 할 수 있습니다.

"things"에 삽입 할 때마다 "things_attributes"에서 새 키가있는 경우 해당 문서의 값을 새 문서 키와 비교 한 후 다시 삽입하면 "things_attributes"에서 얻을 수 있습니다.

따라서 things_attributes에는 findOne ()을 사용하여 필요할 때 쉽게 얻을 수있는 고유 키에 대한 하나의 문서 만 있습니다.


모든 키에 대한 쿼리가 빈번하고 삽입이 자주 발생하지 않는 항목이 많은 데이터베이스의 경우 "모든 키 가져 오기"쿼리의 결과를 캐싱하는 것이 좋습니다. 이것이 한 가지 방법입니다.
Scott
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.