You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB Java:查询匹配文档并过滤嵌套players数组字段

How to Filter Nested Arrays in MongoDB and Return Only Matching Elements (Java Implementation)

Got it, let's work through this problem. You need to fetch documents where at least one player in the players array has a specific nick, and then trim down that array to only include the matching player object. Here are two solid ways to do this with MongoDB's Java tools:

Using MongoDB Core Java Driver

This approach uses MongoDB's aggregation pipeline, which is flexible and works well even if multiple players in the array match the target nick (it'll keep all matching entries).

First, make sure you have the MongoDB Java driver dependency set up. Then use this code:

import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Projections;
import org.bson.Document;
import java.util.Arrays;

public class FilterNestedPlayerArray {
    public static void main(String[] args) {
        // Replace with your MongoDB connection string and database/collection names
        String connectionString = "mongodb://localhost:27017";
        String dbName = "your_database";
        String collectionName = "tournaments";
        String targetNick = "player1";

        // Auto-close the client with try-with-resources
        try (var mongoClient = MongoClients.create(connectionString)) {
            MongoDatabase database = mongoClient.getDatabase(dbName);
            MongoCollection<Document> collection = database.getCollection(collectionName);

            // Build the aggregation pipeline
            var pipeline = Arrays.asList(
                // Step 1: Filter documents that have at least one player with the target nick
                Aggregates.match(Filters.eq("players.nick", targetNick)),
                // Step 2: Project all original fields, but filter the players array to only matches
                Aggregates.project(Projections.fields(
                    // Include all top-level fields you want to keep
                    Projections.include("_id", "type", "prizepool", "name", "start", "end", "buyin", "rake", "prize", "bounty"),
                    // Use $filter to trim the players array
                    Projections.computed("players",
                        new Document("$filter",
                            new Document("input", "$players")
                                .append("as", "player")
                                .append("cond", new Document("$eq", Arrays.asList("$$player.nick", targetNick)))
                        )
                    )
                ))
            );

            // Execute the query and print results
            collection.aggregate(pipeline).forEach(resultDoc -> {
                System.out.println(resultDoc.toJson());
            });
        }
    }
}

Breakdown of the Pipeline:

  • $match Stage: First narrows down the documents to only those that contain the target nick in the players array. This reduces the data we need to process in the next step.
  • $project Stage:
    • Projections.include ensures we keep all the top-level fields from the original document (adjust this list if you need to add/remove fields).
    • $filter iterates over the players array, checking each element's nick against our target. Only matching elements stay in the array.

Using Spring Data MongoDB (For Spring Projects)

If you're using Spring Data MongoDB, you can leverage its fluent API to build the same aggregation logic more cleanly:

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Component;

// Assume this is a Spring component with MongoTemplate injected
@Component
public class TournamentRepositoryHelper {

    private final MongoTemplate mongoTemplate;

    public TournamentRepositoryHelper(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    public Tournament getTournamentWithMatchingPlayer(String targetNick) {
        // Step 1: Match documents with the target nick in players array
        AggregationOperation matchStage = Aggregation.match(Criteria.where("players.nick").is(targetNick));

        // Step 2: Project fields and filter the players array
        AggregationOperation projectStage = Aggregation.project()
                .andInclude("_id", "type", "prizepool", "name", "start", "end", "buyin", "rake", "prize", "bounty")
                .and(Aggregation.filter("players")
                        .as("player")
                        .by(Criteria.where("$$player.nick").is(targetNick)))
                .as("players");

        // Build and execute the aggregation
        Aggregation aggregation = Aggregation.newAggregation(matchStage, projectStage);
        return mongoTemplate.aggregate(aggregation, "tournaments", Tournament.class).getUniqueMappedResult();
    }
}

// Assume you have a Tournament POJO matching your document structure
// public class Tournament {
//     private String id;
//     private int type;
//     private double prizepool;
//     // ... other fields
//     private List<Player> players;
//     // Getters and setters
// }
//
// public class Player {
//     private String nick;
//     private int rank;
//     private double cash;
//     // ... other fields
//     // Getters and setters
// }

Alternative: $elemMatch for Single Matches

If you're certain there will only ever be one player with the target nick per document, you can use $elemMatch in a projection for a simpler query (no aggregation needed):

// Fetch the first matching document with only the matching player in the array
Document result = collection.find(Filters.eq("players.nick", targetNick))
        .projection(Projections.fields(
                Projections.include("_id", "type", "prizepool", ...), // Keep top-level fields
                Projections.elemMatch("players", Filters.eq("nick", targetNick))
        ))
        .first();

Note: This will only return the first matching player in the array if there are multiple entries with the same nick—so use this only when you know duplicates won't exist.

内容的提问来源于stack exchange,提问作者David B

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:28:17