2017-01-25 7 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'は、ドキュメントの配列項目を制限します!これは非常に混乱していた! –

関連する問題