복붙노트

[MONGODB] 컬렉션의 속성을 매핑하기위한 감소 /지도 사용

MONGODB

컬렉션의 속성을 매핑하기위한 감소 /지도 사용

업데이트 : 후속 MongoDB를에이 ​​컬렉션의 모든 키의 이름을 가져옵니다.

크리스티나가 지적한 바와 같이, 하나는 컬렉션의 키를 나열 감소 / MongoDB를의지도를 사용할 수 있습니다 :

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

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

db[mr.result].distinct("_id")

//output: [ "_id", "egg", "hello", "type" ]

만큼 우리가 깊이의 첫 번째 수준에있는 유일한 열쇠를 얻으려면,이 잘 작동합니다. 그러나 더 깊은 수준에있는 그 열쇠를 검색 실패합니다. 우리는 새 레코드를 추가하는 경우 :

db.things.insert({foo: {bar: {baaar: true}}})

그리고 우리가 위에서 + 별개의 조각지도가-줄이기 다시 실행, 우리는 얻을 것이다 :

[ "_id", "egg", "foo", "hello", "type" ] 

그러나 우리는 데이터 구조에서 아래로 중첩 된 바와 baaar 키를 얻을 수 없습니다. 질문 : 어떻게 내가 모든 키를 검색 깊이에 상관없이 자신의 수준을합니까? 이상적으로, 사실은 스크립트와 같은 출력을 같은 생산, 깊이의 모든 수준에 걸어 것입니다 :

["_id","egg","foo","foo.bar","foo.bar.baaar","hello","type"]      

사전에 감사합니다!

해결법

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

    1.OK, 이것은 좀 더 복잡한 일부 재귀를 사용해야하기 때문이다.

    OK, 이것은 좀 더 복잡한 일부 재귀를 사용해야하기 때문이다.

    재귀 일어날 수 있도록하려면 서버에 일부 기능을 저장할 수해야합니다.

    isArray = function (v) {
      return v && typeof v === 'object' && typeof v.length === 'number' && !(v.propertyIsEnumerable('length'));
    }
    
    m_sub = function(base, value){
      for(var key in value) {
        emit(base + "." + key, null);
        if( isArray(value[key]) || typeof value[key] == 'object'){
          m_sub(base + "." + key, value[key]);
        }
      }
    }
    
    db.system.js.save( { _id : "isArray", value : isArray } );
    db.system.js.save( { _id : "m_sub", value : m_sub } );
    
    map = function(){
      for(var key in this) {
        emit(key, null);
        if( isArray(this[key]) || typeof this[key] == 'object'){
          m_sub(key, this[key]);
        }
      }
    }
    
    reduce = function(key, stuff){ return null; }
    
    mr = db.runCommand({"mapreduce" : "things", "map" : map, "reduce" : reduce,"out": "things" + "_keys"});
    db[mr.result].distinct("_id");
    

    당신이 얻을 것이다 결과는 다음과 같습니다

    ["_id", "_id.isObjectId", "_id.str", "_id.tojson", "egg", "egg.0", "foo", "foo.bar", "foo.bar.baaaar", "hello", "type", "type.0", "type.1"]
    

    하나의 명백한 문제는 우리가 여기에 몇 가지 예상치 못한 필드를 추가하고, 여기에 있습니다 :   1. 데이터 _id   2. 0.0 (계란과 유형에 대한)

    문제 # 1에 대한 수정은 상대적으로 쉽다. 그냥지도 기능을 수정합니다. 이 변경 :

    emit(base + "." + key, null); if( isArray...
    

    이에:

    if(key != "_id") { emit(base + "." + key, null); if( isArray... }
    

    문제 # 2는 좀 더 아슬 아슬하다. 당신은 모든 키를 원하고 기술적으로 "egg.0는"유효한 키입니다. 당신은 숫자 키를 무시 m_sub을 수정할 수 있습니다. 그러나이 곳 역화 상황을 볼 수도 쉽다. 그런 다음 당신이이 "0"으로 표시 할, 규칙적인 배열의 연관 배열의 내부를 말해봐. 나는 당신에게 해당 솔루션의 최대의 나머지 부분을 떠날거야.

  2. ==============================

    2.https://github.com/variety/variety : 게이츠 부사장의 영감으로 크리스티나의 응답으로, 나는 정확히 수행 다양한라는 오픈 소스 도구를 개발

    https://github.com/variety/variety : 게이츠 부사장의 영감으로 크리스티나의 응답으로, 나는 정확히 수행 다양한라는 오픈 소스 도구를 개발

    희망 당신은 도움이 될 그것을 찾을 수 있습니다. 질문, 또는를 사용하여 문제가있을 경우 알려주세요.

  3. ==============================

    3.간단한 함수로서;

    간단한 함수로서;

    const getProps = (db, collection) => new Promise((resolve, reject) => {
      db
      .collection(collection)
      .mapReduce(function() {
        for (var key in this) { emit(key, null) }
      }, (prev, next) => null, {
        out: collection + '_keys'
      }, (err, collection_props) => {
        if (err) reject(err)
    
        collection_props
        .find()
        .toArray()
        .then(
          props => resolve(props.map(({_id}) => _id))
        )
      })
    })
    
  4. from https://stackoverflow.com/questions/2997004/using-map-reduce-for-mapping-the-properties-in-a-collection by cc-by-sa and MIT license