2014-05-23 4 views
1

mongodb에서 겹침 투영이 작동하는 방식을 이해하는 데 어려움을 겪고 있습니다.mongodb 투영 겹침 이해

다음은 내 수수께끼를 보여주는 간단한 예입니다 (in-browser mongodb console의 결과).

먼저, I 만들고 간단한 문서에 삽입 :

db.test.find({}, {"systems.1.coords":1, "systems.1":1}); 

//result 
"_id" : ObjectId("537fd3541cdcaf1ba735becb"), 
    "systems" : { 
     "1" : { 
      "coords" : { 
       "y" : 1, 
       "x" : 1 
      } 
     } 
    } 
} 

내가 시스템 (1) "의 전체 내용을 볼 것으로 예상 :

var doc = { 
    id:"universe", 
    systems: { 
    1: { 
     name:"milky_way", 
     coords:{x:1, y:1} 
    } 
    } 
} 

db.test.insert(doc); 
// doc succesfully inserted 

다음에, I는 다소 홀수 투영 시도 "이름 필드를 포함하여. 그러나 "시스템 1. 코드"에 대한 더 깊은 경로가 "시스템 1"에 대한 더 얕은 경로를 덮어 썼다.

나는이 이론 "깊은 경로가 얕은 경로를 무시"테스트하기로 결정 :

여기
db.test.find({}, {"systems.1.coords.x":1, "systems.1.coords":1}); 

//result 
"_id" : ObjectId("537fd3541cdcaf1ba735becb"), 
    "systems" : { 
     "1" : { 
      "coords" : { 
       "y" : 1, // how'd this get here, but for the shallower projection? 
       "x" : 1 
      } 
     } 
    } 
} 

하지 재정의 얕은 하나를했다 내 깊은 투영합니다.

무엇을 제공합니까? 몽고 (mongodb)는 겹치는 예측을 어떻게 다루고 있습니까? 나는 그것에 대한 논리를 찾을 수 없습니다.

편집 :

내 혼란은 "최상위 수준"경로로 계산 무엇에서 유래되었다.

예상대로 작동했습니다 : .findOne({}, {"systems.1":1, "systems":1}) (즉, "좁은"투영으로 보이는 것으로 시작했지만 전체 시스템 집합이 반환됩니다.)

그러나 예상대로 작동하지 않았습니다. .findOne({}, {"systems.1.name":1, "systems.1":1}) (즉, system.1의 이름 필드 만 반환됩니다.)

간략히 말하자면, "한 점"보다 깊은 곳으로 가면 허용되는 대답에서 논의 된 덮어 쓰기가 발생합니다.

답변

1

당신은 이런 종류의 투영을 할 수 없습니다. find()은 허용되는 일반적인 예상이 기본 필드 선택입니다. 당신이 말하는 것은 문서 재 - 모양 짓기이고 그 때문에 .aggregate() 방법을 가진 $project 연산자를 사용할 수 있습니다. 초기 예에 의한

그래서 :

db.test.aggregate([ 
    { "$project": { 
     "coords": "$systems.1.coords", 
     "systems": 1 
    }} 
]) 

과 같이 출력 할 줄 것이다 : 다른 이유 것처럼 다른 필드뿐만 아니라이 이름

{ 
    "_id" : ObjectId("537fe2127cb762d14e2a1007"), 
    "systems" : { 
      "1" : { 
        "name" : "milky_way", 
        "coords" : { 
          "x" : 1, 
          "y" : 1 
        } 
      } 
    }, 
    "coords" : { 
      "x" : 1, 
      "y" : 1 
    } 
} 

주, .find()에서 오는 버전은 선택하려는 필드의 레벨에 대한 중복 된 경로 ("시스템"은 동일 함)가되므로 두 개의 여기에서 할 수있는 방법을 소개합니다.

db.test.aggregate([ 
    { "$project": { 
     "systems": { 
      "1": { 
       "coords": "$systems.1.coords" 
      } 
     }, 
     "systems": 1 
    }} 
]) 

을 그래서 그것을 무효입니다 말하고되지 않으며, 그것이 투영 결과 중 하나는 본질적으로 다른 덮어 쓰기되는 단지이다 : 많은에서

같은 방법으로는 다음과 같은 문을 고려 최상위 레벨은 둘 다 "시스템"이라고합니다.

이것은 기본적으로 .find()에 사용할 수있는 투영 방법으로 이와 같은 작업을하려고 할 때 끝납니다. 따라서 필수적인 부분은 다른 필드 이름이 필요하다는 것입니다. 여기서는 집계 프레임 워크 (집계는 아니지만)로 수행 할 수 있습니다.

+0

응답 해 주셔서 감사합니다. "기본 필드 선택"을 위반하는 것에 대해 자세히 설명해 주시겠습니까? 사례 유스 케이스입니다. 플레이어가 시스템 사이에서 자신의 배송을 이동하면 내 서버는 해당 게임의 데이터 (findOne 사용)에 하위 집합에 대한 투영을 포함하는 문서 하나를 찾습니다. 전체 게임 문서를 가져 오지 않는 유일한 이유는 성능입니다. * 기본 필드 선택이 마음에 드는 것처럼 느껴지지만 어쩌면 다른 깊이에 도달하지 않도록 내 프로젝션을 어떻게 생성하는지 변경할 필요가 있을까요? – akbr

+0

@akbr 문제는 당신이 본질적으로 최상위 레벨의 동일한 필드에서 두 가지를 선택하려고하는 것입니다. 나는 이것을 명확하게 설명하기 위해 $ project를 사용하여 원칙을 확장했다. 이름이 같을 때는 필드를 선택할 수 없으므로 이름을 변경해야합니다. '$ match'와'$ project'와 함께 집계 파이프 라인을 사용하는 것은'.findOne()'와 똑같은 일을하지만 더 유연합니다. 여기서는 성능이 떨어지는 것처럼 보이지 않습니다. 특히 하나의 문서에서 성능이 저하되는 것은 아닙니다. –

+0

나를 통해 걷는 주셔서 감사합니다. 덮어 쓰기 동작이 "두 개의 점들 (two dots in deep)"에서 시작되면 모든 클릭이 발생했습니다. – akbr