2014-03-30 2 views
1

MongoDB에 복잡한 구조 및 하위 문서가있는 모음이 있습니다. 문서는이 같은 구조를 가지고 :MongoDB 하위 문서 찾기 및 결과 정렬

doc1 = { 
    '_id': '12345678', 
    'url': "http//myurl/...", 
    'nlp':{ 
     "status": "OK", 
     "entities": { 
      "0": { 
       "type" : "Person", 
       "relevance": "0.877245", 
       "text" : "Neelie Kroes" 
      }, 
      "1": { 
       "type": "Company", 
       "relevance": "0.36242", 
       "text": "ICANN" 
      }, 
      "2": { 
       "type": "Company", 
       "relevance": "0.265175", 
       "text": "IANA" 
      } 
     } 
    } 
} 


doc2 = { 
    '_id': '987456321', 
    'url': "http//myurl2/...", 
    'nlp':{ 
     "status": "OK", 
     "entities": { 
      "0": { 
       "type": "Company", 
       "relevance": "0.96", 
       "text": "ICANN" 
      }, 
      "1": { 
       "type" : "Person", 
       "relevance": "0.36242", 
       "text" : "Neelie Kroes" 
      }, 
      "2": { 
       "type": "Company", 
       "relevance": "0.265175", 
       "text": "IANA" 
      } 
     } 
    } 
} 

내 작업 "관련성"에 의해 다음 정렬 "유형"과 하위 문서 내부의 "텍스트"를 검색하는 것입니다. 지금은 관련성이 내림차순으로 유형 "사람"과 가치 "닐리 크로스 '의 실체와 모든 레코드를 정렬해야

db.resource.find({ 
    'nlp.entities': { 
     '$elemMatch': {'text': 'Neelie Kroes', 'type': 'Person'} 
    } 
}); 

완벽한 다음 $ elemMatch 연산자와 나는 쿼리를 수행 할 수 있어요.

정상적인 "정렬"을 시도했지만 $ elemMatch의 sort()에 대한 manual said으로 sort()가 배열 요소에 적용 되었기 때문에 결과에 정렬 순서가 반영되지 않을 수 있습니다. $ elemMatch 투영.

실제로 _id : 987456321이 첫 번째로 (관련도는 0.96이지만 ICANN은 참조됩니다.)

일치하는 하위 문서의 관련성에 따라 내 문서를 정렬하려면 어떻게해야합니까?

P .: 문서 구조를 변경할 수 없습니다.

+0

일부 도구에서 덤프가 나오거나 문서가 실제로 mongo 셸에서 어떻게 보이나요? 왜냐하면 당신이 "엔티티"를 표현하는 방식이 배열이 아닌 "서브 문서"이기 때문입니다. 그것들은 어떤 표준 수단으로도 분류 될 수 없습니다. –

답변

1

나는 당신의 문서가 실제적으로 배열을 가지기를 바라고 있지만, $ elemMatch가 당신을 위해 일한다면 그들은 그렇게해야한다.

어쨌든 find를 사용하여 배열의 요소별로 정렬 할 수 없습니다. 관련 경기를 포함 문서의 $match 조건을 수행 한 후, 당신은 다음 _id 필드에 $project "저장"원본 문서를 사용, 그래서 본질적으로

db.collection.aggregate([ 

    // Match the documents that you want, containing the array 
    { "$match": { 
     "nlp.entities": { 
      "$elemMatch": { 
       "text": "Neelie Kroes", 
       "type": "Person" 
      } 
     } 
    }}, 

    // Project to "store" the whole document for later, duplicating the array 
    { "$project": { 
     "_id": { 
      "_id": "$_id", 
      "url": "$url", 
      "nlp": "$nlp"   
     }, 
     "entities": "$nlp.entities" 
    }}, 

    // Unwind the array to de-normalize 
    { "$unwind": "$entities" }, 

    // Match "only" the relevant entities 
    { "$match": { 
     "entities.text": "Neelie Kroes", 
     "entities.type": "Person" 
    }}, 

    // Sort on the relevance 
    { "$sort": { "entities.relevance": -1 } }, 

    // Restore the original document form 
    { "$project": { 
     "_id": "$_id._id", 
     "url": "$_id.url", 
     "nlp": "$_id.nlp" 
    }} 
]) 

:하지만 당신은 .aggregate()를 사용하여이 작업을 수행 할 수있는 경우가있다 $unwind은 "entities"배열의 "copy"입니다.

다음 $match은 배열 내용을 관련성있는 항목으로 "필터링"합니다. 그런 다음 $sort을 "일치하는"문서에 적용합니다.

"원본"문서가 _id에 저장되었으므로 $project을 사용하여 문서가 실제로 시작해야하는 구조를 "복원"합니다.

배열의 일치 요소를 "정렬"하는 방법입니다.

참고 부모 문서의 배열 내에서 여러 "일치"했다 경우, 당신은 완료하려면 "관련성"필드의 $ 최대 값을 얻기 위해 추가 $group 단계를 고용해야한다는 것을 당신의 종류.

+0

완벽하게 작동합니다. 처음에는 천천히하지만, 후에는 매우 빠릅니다. 집계 함수는 RAM, 캐시 또는 다른 고속 시스템에 저장되어 있습니까? 다시 감사합니다. –