AggregationPipelineQueryNode extends ExternalSet { public boolean project(final Iterable<ProjectionElemList> projections) { if (projections == null || !projections.iterator().hasNext()) { return false; } final List<Bson> projectOpts = new LinkedList<>(); final Set<String> bindingNamesUnion = new HashSet<>(); Set<String> bindingNamesIntersection = null; for (final ProjectionElemList projection : projections) { if (projection.getElements().isEmpty()) { return false; } final Document valueDoc = new Document(); final Document hashDoc = new Document(); final Document typeDoc = new Document(); final Set<String> projectionBindingNames = new HashSet<>(); for (final ProjectionElem elem : projection.getElements()) { String to = elem.getTargetName(); if (!isValidFieldName(to)) { to = replace(to); } String from = elem.getSourceName(); if (varToOriginalName.containsValue(from)) { from = varToOriginalName.inverse().get(from); } projectionBindingNames.add(to); if (to.equals(from)) { valueDoc.append(to, 1); hashDoc.append(to, 1); typeDoc.append(to, 1); } else { valueDoc.append(to, valueFieldExpr(from)); hashDoc.append(to, hashFieldExpr(from)); typeDoc.append(to, typeFieldExpr(from)); } } bindingNamesUnion.addAll(projectionBindingNames); if (bindingNamesIntersection == null) { bindingNamesIntersection = new HashSet<>(projectionBindingNames); } else { bindingNamesIntersection.retainAll(projectionBindingNames); } projectOpts.add(new Document() .append(VALUES, valueDoc) .append(HASHES, hashDoc) .append(TYPES, typeDoc) .append(LEVEL, "$" + LEVEL) .append(TIMESTAMP, "$" + TIMESTAMP)); } if (projectOpts.size() == 1) { pipeline.add(Aggregates.project(projectOpts.get(0))); } else { final String listKey = "PROJECTIONS"; final Bson projectIndividual = Projections.fields( Projections.computed(VALUES, "$" + listKey + "." + VALUES), Projections.computed(HASHES, "$" + listKey + "." + HASHES), Projections.computed(TYPES, "$" + listKey + "." + TYPES), Projections.include(LEVEL), Projections.include(TIMESTAMP)); pipeline.add(Aggregates.project(Projections.computed(listKey, projectOpts))); pipeline.add(Aggregates.unwind("$" + listKey)); pipeline.add(Aggregates.project(projectIndividual)); } assuredBindingNames.clear(); bindingNames.clear(); assuredBindingNames.addAll(bindingNamesIntersection); bindingNames.addAll(bindingNamesUnion); return true; } AggregationPipelineQueryNode(final MongoCollection<Document> collection, final StatementPattern baseSP);   AggregationPipelineQueryNode(final MongoCollection<Document> collection,
            final List<Bson> pipeline, final Set<String> assuredBindingNames,
            final Set<String> bindingNames, final BiMap<String, String> varToOriginalName); @Override boolean equals(final Object o); @Override int hashCode(); @Override CloseableIteration<BindingSet, QueryEvaluationException> evaluate(final BindingSet bindings); @Override Set<String> getAssuredBindingNames(); @Override Set<String> getBindingNames(); @Override AggregationPipelineQueryNode clone(); @Override String getSignature(); boolean joinWith(final StatementPattern sp); boolean project(final Iterable<ProjectionElemList> projections); boolean extend(final Iterable<ExtensionElem> extensionElements); boolean filter(final ValueExpr condition); boolean distinct(); void requireSourceDerivationDepth(final int requiredLevel); void requireSourceTimestamp(final long t); List<Bson> getTriplePipeline(final long timestamp, final boolean requireNew);  }
@Test public void testProject() { final AggregationPipelineQueryNode base = new AggregationPipelineQueryNode( collection, new LinkedList<>(), Sets.newHashSet("x", "y"), Sets.newHashSet("x", "y", "opt"), HashBiMap.create()); ProjectionElemList singleProjection = new ProjectionElemList(); singleProjection.addElement(new ProjectionElem("x", "z")); singleProjection.addElement(new ProjectionElem("y", "y")); List<ProjectionElemList> projections = Arrays.asList(singleProjection); AggregationPipelineQueryNode node = base.clone(); boolean success = node.project(projections); Assert.assertTrue(success); Assert.assertEquals(1, node.getPipeline().size()); Assert.assertEquals(Sets.newHashSet("z", "y"), node.getAssuredBindingNames()); Assert.assertEquals(Sets.newHashSet("z", "y"), node.getBindingNames()); ProjectionElemList p1 = new ProjectionElemList(); p1.addElement(new ProjectionElem("x", "solution")); ProjectionElemList p2 = new ProjectionElemList(); p2.addElement(new ProjectionElem("y", "solution")); ProjectionElemList p3 = new ProjectionElemList(); p3.addElement(new ProjectionElem("x", "x")); p3.addElement(new ProjectionElem("x", "solution")); p3.addElement(new ProjectionElem("y", "y")); projections = Arrays.asList(p1, p2, p3); node = base.clone(); success = node.project(projections); Assert.assertTrue(success); Assert.assertEquals(3, node.getPipeline().size()); Assert.assertEquals(Sets.newHashSet("solution"), node.getAssuredBindingNames()); Assert.assertEquals(Sets.newHashSet("x", "y", "solution"), node.getBindingNames()); node = base.clone(); success = node.project(Arrays.asList()); Assert.assertFalse(success); Assert.assertEquals(base, node); }