mongodbaggregation-frameworkspring-data-mongodbmongo-java-drivermongo-java

MongoDB Java Error: A pipeline stage specification object must contain exactly one field


I am trying to get result of this MongoDB query on java.

db.fileTree.aggregate([
    {
        $match: {
            "_id": "6062144bb25e4809548ef246",
        }
    }, 
    {
        $unwind: "$children"
    },
    {
        $match: {
            "children.fileName": "Test1"
        }
    },
    {
        $project: {
            "_id": 0,
            "fileId": "$children.fileId",
            "fileName": "$children.fileName",
            "directory": "$children.directory",
        }
    }
]).pretty()

The query works perfectly fine and it is not showing anything when there is no data. But, the query when executed from java is producing the following error:

com.mongodb.MongoCommandException: Command failed with error 40323 (Location40323): 'A pipeline stage specification object must contain exactly one field.' on server localhost:27017. The full response is {"ok": 0.0, "errmsg": "A pipeline stage specification object must contain exactly one field.", "code": 40323, "codeName": "Location40323"}

ChildFile findChildInParent(String parentId, String fileName) {
        BasicDBObject idFilter = new BasicDBObject().append("_id", parentId);
        BasicDBObject matchId = new BasicDBObject().append("$match", idFilter);
        BasicDBObject unwindChildren = new BasicDBObject().append("$unwind", "$children");
        BasicDBObject childNameFilter = new BasicDBObject().append("children.fileName", fileName);
        BasicDBObject matchChildName = new BasicDBObject().append("$match", childNameFilter);
        BasicDBObject projections = new BasicDBObject()
                .append("_id", 0)
                .append("fileId", "$children.fileId")
                .append("fileName", "$children.fileName")
                .append("directory", "$children.directory");

        List<ChildFile> childFiles = fileCollection.aggregate(
                List.of(matchId, unwindChildren, matchChildName, projections),
                ChildFile.class
        ).into(new ArrayList<>());

        return childFiles.size() > 0 ? childFiles.get(0) : null;
    }

Am I missing anything here? Any help is really appreciated. Thanks 😃!


Solution

  • There is a typo in your code, you are missing $ for children field

    Should be:

    BasicDBObject unwindChildren = new BasicDBObject().append("$unwind", "$children")
    

    Instead of:

    BasicDBObject unwindChildren = new BasicDBObject().append("$unwind", "children")
    

    Also missing $poject stage:

    BasicDBObject projections = new BasicDBObject()
            .append("_id", 0)
            .append("fileId", "$children.fileId")
            .append("fileName", "$children.fileName")
            .append("directory", "$children.directory");
    
    BasicDBObject projectionStage = new BasicDBObject().append("$project", projections);
    
    List<ChildFile> childFiles = fileCollection.aggregate(
            List.of(matchId, unwindChildren, matchChildName, projectionStage),
            ChildFile.class
    ).into(new ArrayList<>());