2017-01-25 1 views
2

내장 배열을 기반으로 문서를 필터링하는 방법은 무엇입니까?

db.scores.find(
    { results: { $elemMatch: { $gte: 80, $lt: 85 } } } 
) 

특히이 쿼리, this page를 검토 한 후 나는 다음과 같은 수입

import static com.mongodb.client.model.Filters.and; 
import static com.mongodb.client.model.Filters.elemMatch; 
import static com.mongodb.client.model.Filters.eq; 
import static com.mongodb.client.model.Projections.excludeId; 
import static com.mongodb.client.model.Projections.fields; 
import static com.mongodb.client.model.Projections.include; 

을 사용 그리고 비슷한 작업을 수행하려면 다음 코드를 내놓았다 (ARRAY_FIELD_NAME = "myArray")

MongoCollection<Document> collection = mongoDB.getCollection(COLLECTION_NAME); 

Bson filters = and(eq("userId", userId), elemMatch(ARRAY_FIELD_NAME, eq("id", id))); 
Bson projections = fields(include(ARRAY_FIELD_NAME), excludeId()); 

List<Document> results = (List<Document>) collection.find(filters).projection(projections).first().get(ARRAY_FIELD_NAME); 
if (CollectionUtils.isEmpty(results)) { 
    return null; 
} 
if (results.size() > 1) { 
    throw new ApiException(String.format("Multiple results matched (User ID: %s, Array item ID: %s)", userId, id)); 
} 
return results.get(0); 

다음 구조를 가진 문서를 필터링하려면

{ 
    "_id": { 
     "$oid": "588899721bbabc26865f41cc" 
    }, 
    "userId": 55, 
    "myArray": [ 
     { 
      "id": "5888998e1bbabc26865f41d2", 
      "title": "ABC" 
     }, 
     { 
      "id": "5888aaf41bbabc3200e252aa", 
      "title": "ABC" 
     } 
    ] 
} 

그러나 myArray 필드에서 하나의 항목 만 가져 오는 대신 항상 두 항목을 모두 가져옵니다!

예상대로

MongoCollection<Document> collection = mongoDB.getCollection(COLLECTION_NAME); 

List<Bson> aggregationFlags = new ArrayList<>(); 
aggregationFlags.add(new Document("$unwind", "$" + ARRAY_FIELD_NAME)); 
aggregationFlags.add(new Document("$match", new Document("userId", userId).append(ARRAY_FIELD_NAME + ".id", id))); 
aggregationFlags.add(new Document("$project", new Document("_id", 0).append(ARRAY_FIELD_NAME, "$" + ARRAY_FIELD_NAME))); 

return (Document) collection.aggregate(aggregationFlags).first().get(ARRAY_FIELD_NAME); 

이 왜 문제의 시작 부분에 표시되는 쿼리로 동일하게 동작한다 코드의 첫 번째 조각, 결과를 필터링하지 않습니다 따르고 나를 위해 일한 유일한 코드 ?

결과를 "집계"할 필요가 없습니다. 사용자 ID와 배열 항목 ID를 사용하여 결과를 "필터링"해야합니다.

답변

1

$elemMatch(projection)을 사용해야합니다. 아래와 같은 것이 효과가 있습니다.

import static com.mongodb.client.model.Projections.elemMatch; 

Bson filters = and(eq("userId", userId)); 
Bson projections = fields(elemMatch(ARRAY_FIELD_NAME, eq("id", id)), excludeId()); 
+1

처음에는 답이 내 문제를 해결하는 방법을 볼 수 없었습니다. 그러나 나는 투영법과 필터에 대한'elemMatch' 문서를 계속 읽고 있으며, 지금은 이해하고 있습니다. 'Filters.elemMatch'는 일치하는 배열 필터로 문서를 필터링합니다. 'Projections.elemMatch'는 문서의 배열 항목을 제한합니다! 이것은 매우 혼란 스러웠습니다! –

관련 문제