2017-10-01 1 views
0

를 사용할 때 다음과 같은 형식의 문서와 모음이 제 1 서브 - 문서 이상을 투사하는 방법 :

{ 
    "_id" : { "$oid" : "67bg............"}, 
    "ID" : "xxxxxxxx", 
    "senses" : [ 
     { 
      "word" : "hello", 
      "lang" : "EN", 
      "source" : "EN_DICTIONARY" 
     }, 
     { 
      "word" : "coche", 
      "lang" : "ES", 
      "source" : "ES_DICTIONARY" 
     }, 
     { 
      "word" : "bye", 
      "lang" : "EN", 
      "source" : "EN_DICTIONARY" 
     } 
    ] 
} 

내가 lang=X과 함께 적어도 하나의 의미가 일치하는 모든 문서를 찾으려면를 source=Y과 일치하는 senses 만 일치하는 문서를 반환하십시오. lang=Xsource=Y

DBObject sensesQuery = new BasicDBObject(); 
sensesQuery.put("lang", "EN"); 
sensesQuery.put("source", "EN_DICTIONARY"); 
DBObject matchQuery = new BasicDBObject("$elemMatch",sensesQuery); 

DBObject fields = new BasicDBOject(); 
fields.put("senses",matchQuery); 

DBObject projection = new BasicDBObject(); 
projection.put("ID",1) 
projection.put("senses",matchQuery); 
DBCursor cursor = collection.find(fields,projection) 

while(cursor.hasNext()) { 
    ... 
} 

내 쿼리가 투사에 일치하는 문서를 작동하지만,하지 :

나는이 시도. 내 쿼리를 실행하는 경우 예를 들어 위의 문서를 촬영,이 결과를 얻을 :

{ 
    "_id" : { "$oid" : "67bg............"}, 
    "ID" : "xxxxxxxx", 
    "senses" : [ 
     { 
      "word" : "hello", 
      "lang" : "EN", 
      "source" : "EN_DICTIONARY" 
     } 
    ] 
} 

을하지만 난이 원하는 : 나는 통합에 대해 읽어하지만 난 그것을 사용하는 방법을 이해하지 못했다

{ 
    "_id" : { "$oid" : "67bg............"}, 
    "ID" : "xxxxxxxx", 
    "senses" : [ 
     { 
      "word" : "hello", 
      "lang" : "EN", 
      "source" : "EN_DICTIONARY" 
     }, 
     { 
      "word" : "bye", 
      "lang" : "EN", 
      "source" : "EN_DICTIONARY" 
     } 
    ] 
} 

MongoDB Java 드라이버에서.

감사

답변

1

당신은 필터에로 투사 aswell에 $elemMatch 연산자를 사용하고 있습니다. the docs

가입일

$elemMatch$elemMatch 연산자는 조건에 합치 첫 번째 원소를 포함하는 질의 결과에서 필드의 내용을 제한한다.

그래서, 당신은 을보고있는 동작은 elemMatch - 인 - 어 - 투영 예상되는 동작입니다. 당신이 필터 조건에 맞는 문서 내에서 senses 배열의 모든 하위 문서를 투사 할 경우

당신은이를 사용할 수 있습니다 : 당신이 일치 만 하위 문서를 투사 할 경우,

projection.put("senses", 1); 

을하지만 당신의 필터 조건이 $elemMatch이면 $elemMatch 조건과 일치하는 첫 번째 요소 만 반환하기 때문에 작동하지 않습니다.

Document filter = new Document("senses.lang", "EN").append("senses.source", "EN_DICTIONARY"); 

DBObject filterExpression = new BasicDBObject(); 
filterExpression.put("input", "$senses"); 
filterExpression.put("as", "sense"); 
filterExpression.put("cond", new BasicDBObject("$and", Arrays.<Object>asList(
     new BasicDBObject("$eq", Arrays.<Object>asList("$$sense.lang", "EN")), 
     new BasicDBObject("$eq", Arrays.<Object>asList("$$sense.source", "EN_DICTIONARY"))) 
)); 

BasicDBObject projectionFilter = new BasicDBObject("$filter", filterExpression); 

AggregateIterable<Document> documents = collection.aggregate(Arrays.asList(
     new Document("$match", filter), 
     new Document("$project", new Document("senses", projectionFilter)))); 

for (Document document : documents) { 
    logger.info("{}", document.toJson()); 
} 

결과 출력은 다음과 같습니다 :

2017-10-01 17:15:39 [main] INFO c.s.mongo.MongoClientTest - { "_id" : { "$oid" : "59d10cdfc26584cd8b7a0d3b" }, "senses" : [{ "word" : "hello", "lang" : "EN", "source" : "EN_DICTIONARY" }, { "word" : "bye", "lang" : "EN", "source" : "EN_DICTIONARY" }] } 

업데이트 여기

db.collection.aggregate([ // matches documents with a senses sub document having the given lang and source values {$match: {'senses.lang': 'EN', 'senses.source': 'EN_DICTIONARY'}}, // projects on the senses sub document and filters the output to only return sub // documents having the given lang and source values {$project: { senses: { $filter: { input: "$senses", as: "sense", cond: { $eq: [ "$$sense.lang", 'EN' ], $eq: [ "$$sense.source", 'EN_DICTIONARY' ] } } } } } ]) 

는 MongoDB의 자바 드라이버를 사용하여 해당 집계 호출이다 : 당신의 대안은 예를 들어, 통합 프레임 워크를 사용하는 것입니다 1
:이 댓글 다음 :

오랜 기간 동안 테스트가 왜 느린지를 이해하기 위해 "$ match"매개 변수가 작동하지 않는 것으로 나타났습니다. 쿼리는 적어도 하나의 의미가있는 레코드 만 선택해야합니다. source = Y 및 lang = X와 그들을 프로젝트,하지만 쿼리는 [] = 감각으로 나에게 문서를 반환

이 필터 : new Document("senses.lang", "EN").append("senses.source", "EN_DICTIONARY")senses 속성이되지 않으며 빈 senses 속성이 문서를 일치 문서를 일치하지 않습니다.

{ 
    "_id" : ObjectId("59d72a24c26584cd8b7b70a5"), 
    "ID" : "yyyyyyyy" 
} 

{ 
    "_id" : ObjectId("59d72a3ac26584cd8b7b70ae"), 
    "ID" : "zzzzzzzzz", 
    "senses" : [] 
} 

을 그리고 다시는 위의 코드를 실행하고 난 여전히 원하는 결과를 얻을 :이를 확인하려면 내 자신의 컬렉션에 다음의 서류를 추가했다.

나는 위의 코드가 작동하지 않는다는 내용이 거짓 부정적이거나 쿼리하는 문서가 내가 사용한 샘플과 다른 것으로 의심됩니다. 당신은 당신이 할 수 너 자신을 위해이 문제를 진단하는 데 도움이

은 ...

  • 예를 들어, 다른 사업자와 주위 플레이 $match 단계에와 $exists 조작없이 동일하게 동작합니다

    new Document("senses", new BasicDBObject("$exists", true)) 
         .append("senses.lang", new BasicDBObject("$eq", "EN")) 
         .append("senses.source", new BasicDBObject("$eq", "EN_DICTIONARY")) 
    
  • $match 단계가 생산 정확히 확인하기 위해 $project 단계를 제거합니다.

+0

AggregationOutput에는 .into(); 메소드가 없습니다. –

+0

v3.5에서 그렇습니다. :) 그 이유는 이것이 목록으로 출력하기위한 구문 론적 설탕이기 때문에 부차적 인 문제입니다. 나는 AggregateIterable을 반환하는 대답을 업데이트했다. 그 대답의 요점은, (1) 투영법에서 elemMatch가 왜 첫 번째 엔트리를 반환하는지, (2) 집계 프레임 워크를 통해 동일한 필터를 수행하는 방법, (3) MongoDB Java 드라이버. – glytching

+0

좋아요, 이제는 ($ eq : [ "$$ sense.source", 'EN_DICTIONARY'] "를 filterExpression에 추가하는 첫 번째 조건 ("$$ sense.lang ","EN ")? –

관련 문제