diff --git a/plugin/trino-mongodb/src/main/java/io/trino/plugin/mongodb/MongoSession.java b/plugin/trino-mongodb/src/main/java/io/trino/plugin/mongodb/MongoSession.java index 846438ae0543..75c0bbd0c754 100644 --- a/plugin/trino-mongodb/src/main/java/io/trino/plugin/mongodb/MongoSession.java +++ b/plugin/trino-mongodb/src/main/java/io/trino/plugin/mongodb/MongoSession.java @@ -490,17 +490,13 @@ public MongoCursor execute(MongoTableHandle tableHandle, List projectedColumns = tableHandle.getProjectedColumns(); checkArgument(projectedColumns.isEmpty() || projectedColumns.containsAll(columns), "projectedColumns must be empty or equal to columns"); - Document output = new Document(); - // Starting in MongoDB 4.4, it is illegal to project an embedded document with any of the embedded document's fields - // (https://www.mongodb.com/docs/manual/reference/limits/#mongodb-limit-Projection-Restrictions). So, Project only sufficient columns. - for (MongoColumnHandle column : projectSufficientColumns(columns)) { - output.append(column.getQualifiedName(), 1); - } + Document projection = buildProjection(columns); + MongoCollection collection = getCollection(tableHandle.getRemoteTableName()); Document filter = buildFilter(tableHandle); - FindIterable iterable = collection.find(filter).projection(output).collation(SIMPLE_COLLATION); + FindIterable iterable = collection.find(filter).projection(projection).collation(SIMPLE_COLLATION); tableHandle.getLimit().ifPresent(iterable::limit); - log.debug("Find documents: collection: %s, filter: %s, projection: %s", tableHandle.getSchemaTableName(), filter, output); + log.debug("Find documents: collection: %s, filter: %s, projection: %s", tableHandle.getSchemaTableName(), filter, projection); if (cursorBatchSize != 0) { iterable.batchSize(cursorBatchSize); @@ -509,6 +505,25 @@ public MongoCursor execute(MongoTableHandle tableHandle, List columns) + { + Document output = new Document(); + + // _id is always projected by mongodb unless its explicitly excluded. + // We exclude it explicitly at the start and later include it if its present within columns list. + // https://www.mongodb.com/docs/drivers/java/sync/current/fundamentals/builders/projections/#exclusion-of-_id + output.append("_id", 0); + + // Starting in MongoDB 4.4, it is illegal to project an embedded document with any of the embedded document's fields + // (https://www.mongodb.com/docs/manual/reference/limits/#mongodb-limit-Projection-Restrictions). So, Project only sufficient columns. + for (MongoColumnHandle column : projectSufficientColumns(columns)) { + output.append(column.getQualifiedName(), 1); + } + + return output; + } + /** * Creates a set of sufficient columns for the input projected columns. For example, * if input {@param columns} include columns "a.b" and "a.b.c", then they will be projected from a single column "a.b". diff --git a/plugin/trino-mongodb/src/test/java/io/trino/plugin/mongodb/TestMongoSession.java b/plugin/trino-mongodb/src/test/java/io/trino/plugin/mongodb/TestMongoSession.java index c0d8c0fac97e..d0611b3f0acd 100644 --- a/plugin/trino-mongodb/src/test/java/io/trino/plugin/mongodb/TestMongoSession.java +++ b/plugin/trino-mongodb/src/test/java/io/trino/plugin/mongodb/TestMongoSession.java @@ -49,6 +49,34 @@ public class TestMongoSession private static final MongoColumnHandle COL5 = createColumnHandle("col5", BIGINT); private static final MongoColumnHandle COL6 = createColumnHandle("grandparent", createUnboundedVarcharType(), "parent", "col6"); + private static final MongoColumnHandle ID_COL = new MongoColumnHandle("_id", ImmutableList.of(), ObjectIdType.OBJECT_ID, false, false, Optional.empty()); + + @Test + public void testBuildProjectionWithoutId() + { + List columns = ImmutableList.of(COL1, COL2); + + Document output = MongoSession.buildProjection(columns); + Document expected = new Document() + .append(COL1.getBaseName(), 1) + .append(COL2.getBaseName(), 1) + .append(ID_COL.getBaseName(), 0); + assertEquals(output, expected); + } + + @Test + public void testBuildProjectionWithId() + { + List columns = ImmutableList.of(COL1, COL2, ID_COL); + + Document output = MongoSession.buildProjection(columns); + Document expected = new Document() + .append(COL1.getBaseName(), 1) + .append(COL2.getBaseName(), 1) + .append(ID_COL.getBaseName(), 1); + assertEquals(output, expected); + } + @Test public void testBuildQuery() {