Here's a solution I came up with:
    Stream<Document> stream = Stream.of(
            new Document("A", "v1"),
            new Document("A", "v2"),
            new Document("B", "v1"),
            new Document("C", "v1"),
            new Document("C", "v2")
    );
    Iterator<Document> iterator = stream.iterator();
    Stream<GroupedDocument> result = Stream.generate(new Supplier<GroupedDocument>() {
        Document lastDoc = null;
        @Override
        public GroupedDocument get() {
            try {
                Document doc = Optional.ofNullable(lastDoc).orElseGet(iterator::next);
                String id = doc.getId();
                GroupedDocument gd = new GroupedDocument(doc.getId());
                gd.getVersions().add(doc.getVersion());
                if (!iterator.hasNext()) {
                    return null;
                }
                while (iterator.hasNext() && (doc = iterator.next()).getId().equals(id)) {
                    gd.getVersions().add(doc.getVersion());
                }
                lastDoc = doc;
                return gd;
            } catch (NoSuchElementException ex) {
                return null;
            }
        }
    });
Here are the Document and GroupedDocument classes:
class Document {
    private String id;
    private String version;
    public Document(String id, String version) {
        this.id = id;
        this.version = version;
    }
    public String getId() {
        return id;
    }
    public String getVersion() {
        return version;
    }
}
class GroupedDocument {
    private String id;
    private List<String> versions;
    public GroupedDocument(String id) {
        this.id = id;
        versions = new ArrayList<>();
    }
    public String getId() {
        return id;
    }
    public List<String> getVersions() {
        return versions;
    }
    @Override
    public String toString() {
        return "GroupedDocument{" +
                "id='" + id + '\'' +
                ", versions=" + versions +
                '}';
    }
}
Note that the resulting stream is an infinite stream. After all the groups there will be an infinite number of nulls. You can take all the elements that are not null by using takeWhile in Java 9, or see this post.