2013-07-27 2 views
0

나는 다음과 같은 문서의 컬렉션이 있습니다쿼리 하위 배열 곳

{ 
"_id" : ObjectId("51f1fd2b8188d3117c6da352"), 
"cust_id" : "abc1234", 
"ord_date" : ISODate("2012-10-03T18:30:00Z"), 
"status" : "A", 
"price" : 27, 
"items" : [{ 
    "sku" : "mmm", 
    "qty" : 5, 
    "price" : 2.5 
}, { 
    "sku" : "nnn", 
    "qty" : 5, 
    "price" : 2.5 
}] 
} 

내가 "항목"의 분야에서 "여기서 $"를 사용하려면, 그래서 뭔가 다음과 같습니다 :

{$where:"this.items.sku==mmm"} 

어떻게하면됩니까? 필드가 배열 유형이 아닌 경우 작동합니다.

답변

0

this.items.sku을 변수 mmm과 비교합니다.이 값은 초기화되지 않았으므로 unefined입니다. 원하는 작업은 배열을 반복하고 각 항목을 문자열 'mmm'과 비교하는 것입니다. 이 예는 전달 함수가 항목 중 적어도 하나에 대한 true을 반환 할 때, true를 반환 배열 방법을 some 사용하여이 작업을 수행합니다

{$where:"return this.items.some(function(entry){return entry.sku =='mmm'})"} 

하지만 실제로는, 을하지합니다. JohnnyHK의 답변에 대한 답변에서 "내 서비스는 사용자와 mongodb 사이의 인터페이스 일 뿐이며 현장 고객이 원하는 것을 전혀 모르고 있습니다."라고 말했습니다. 당신은 실제로 당신의 유스 케이스를 설명하지 않고 있지만, 당신이 이것을 더 잘 풀 수 있다고 확신합니다.

  • 일반 쿼리로 수행 할 수있는 경우에도 $ where 연산자는 Javascript 엔진을 호출합니다. 이는 불필요한 성능 오버 헤드를 의미합니다.
  • 컬렉션의 모든 단일 문서가 함수에 전달되므로 인덱스가 있으면 사용할 수 없습니다.
  • 클라이언트가 제공 한 것으로부터 javascript 함수가 생성 될 때 제대로 살리거나 탈출하지 않도록주의해야합니다. 그렇지 않으면 응용 프로그램이 코드 삽입에 취약 해집니다.
+0

@ Phalguni이 답변의 이전 버전은 잘못된 자바 스크립트 기능을 포함하고 있습니다. 이제 수정되었습니다. (this._id이) 기능지도() { \t \t 개의 발광, 을}, 가 감소 : db.runCommand ({맵리 듀스 : "주문", 지도 – Philipp

+0

나는 다음 쿼리를 실행 기능 (키 감소, 값) { \t 리턴 값; } 마무리 : 함수의 Finalize (키 감소) {창 저감 \t; } 쿼리 { "$"는 "(this.items.some를 반환 함수 (항목) {entry.sku == 'mmm'}) "}, out : {merge :"map_reduce "} });)하지만 작동하지 않습니다 – Phalguni

+0

문제가 생겼습니다 : 쿼리는 다음과 같아야합니다. $ 여기서 "return this.items.some (function entry) {return entry.sku == 'mmm'}) "}, 내부 함수가 return 문이 없음. – Phalguni

2

이렇게하려면 $where 연산자가 필요하지 않습니다. 즉, items 배열의 각 요소를 확인 않을거야 그래서 왜 $where가, 그냥거야, 그 연산자의 값을 자바 스크립트로 실행, 작동하지 않는 경우에 대해서는

{ "items.sku": mmm } 

: 단지의 쿼리 객체를 사용 일반 개체로 items을 처리하고 해당 sku 속성 (정의되지 않음)을 mmm과 비교하십시오.

+0

나는 둘 다 사용해야하는 상황이 있는데, 내 서비스는 사용자와 mongodb 간의 인터페이스 일 뿐이며, 필드 클라이언트가 저장하고자하는 것을 전혀 모르고 있으므로 클라이언트가 "items.sku == 음, "작동해야합니다, 나는 간단한 쿼리를 사용할 수있는 것을 알고 있지만 $ – Phalguni

+0

에 대한 해결 방법입니다. 그래서"for 루프 "에 $ where 절을 추가 할 수 있습니까? – Phalguni

0

나는이 질문에 덧붙여 당신의 의견을 읽었습니다. 사용자가 일반적으로 문서 내의 배열에 저장하는 일부 특성을 추가 할 수있는 것 같습니다. 클라이언트는 일반적인 방식으로 문서의 임의 쌍을 쿼리 할 수 ​​있어야합니다. 이를 달성하기위한 패턴은 일반적으로 다음과 같습니다.

{ 
    . 
    . 
    attributes:[ 
    {k:"some user defined key", 
     v:"the value"}, 
    {k: ,v:} 
     . 
     . 
    ] 
} 

귀하의 경우 항목은 속성입니다. 이제 문서를 얻기 위해, 쿼리가 같은 것입니다 :이 서비스는 데이터를 조회 할 수있는 방법을 제공 할 수 있습니다

eg) 
db.collection.find({attributes:{$elemMatch:{k:"sku",v:"mmm"}}}); 
(index attributes.k, attributes.v) 

을하고 클라이언트를시키는 것은 무엇 K를 지정, V 쌍입니다. 이 디자인의 한 가지 경고는 문서에 16MB 제한이 있음을 항상 알고 있습니다 (GridFS를 적합하게 만드는 사용 사례가없는 경우). 이것을 제어하는 ​​데 도움이되는 $ slice와 같은 함수가 있습니다.

+0

Dyalan 당신이 맞 겠지만, 사용자가 "items.qty> 5"와 같은 검색어를 원할 경우이 경우에는 작동하지 않을 것입니다. "$ where"를 @philip으로 사용하는 것이 좋습니다. 말했다. – Phalguni

+0

이 쿼리를 수행 할 수 있습니다. 예를 들면 다음과 같습니다. db.col.find ({attributes : {$ elemMatch : {k0 : "sku", v0 : "mmm", k1 : "qty", v1 : {$ gt : 5}}}} 색인은 db.col.ensureIndex ({ "attributes.k0": 1, "attributes.v0": 1, "attributes.k1": 1, "attributes.v1": 1, "attributes.k2" 1, "attributes.v2": 1}); –