Skip to content

Question regarding group and replaceRoot methods #2076

Description

@jbellic

Hi, unfortunately I have issues in converting a working mongodb query to morphia (java) code and the existing documentation didn't help so far.

Here is the working mongodb query delivering correct results:

db.getCollection("stock_exchange_companies_sentiment_statistics").aggregate([
    { $match: { "period": "H1" } },
    { $sort: { "dateTime": -1 } },
    { $group: { _id: "$stockExchangeCompany", latestStatistics: { $first: "$$ROOT" } } },
    { $replaceRoot: { newRoot: "$latestStatistics" } },
    { $sort: { "stockExchangeCompany": 1 } },
    { $skip: 10 },
    { $limit: 10 },
])

Morphia Entity:

@Data
@Builder
@AllArgsConstructor
@RequiredArgsConstructor
@FieldNameConstants
@Entity("stock_exchange_companies_sentiment_statistics")
@Indexes({
        @Index(fields = @Field(value = "stockExchangeCompany", type = IndexType.ASC), options = @IndexOptions(name = "stock_exchange_companies_sentiment_statistics_company_index")),
        @Index(fields = @Field(value = "period", type = IndexType.ASC), options = @IndexOptions(name = "stock_exchange_companies_sentiment_statistics_period_index")),
        @Index(fields = @Field(value = "dateTime", type = IndexType.DESC), options = @IndexOptions(name = "stock_exchange_companies_sentiment_statistics_date_time_index")),
})
public class StockExchangeCompanySentimentStatistics {

    @Id
    private String id;

    @Reference
    private StockExchangeCompany stockExchangeCompany;
    private ZonedDateTime dateTime;
    private StockExchangeCompanySentimentStatisticsPeriod period;
    private Integer totalContentVolume;
    private Integer positiveContentVolume;
    private Integer negativeContentVolume;
    private Integer neutralContentVolume;
    private BigDecimal positiveContentRate;
    private BigDecimal negativeContentRate;
    private BigDecimal neutralContentRate;
    private BigDecimal rangeContentVolumeAverage;
    private BigDecimal netSentiment;
    private BigDecimal subjectivity;
}

And the attempt of converting the query to java code:

 datastore.aggregate(StockExchangeCompanySentimentStatistics.class)
                .match(Filters.eq("period", "H1"))
                .sort(dev.morphia.aggregation.experimental.stages.Sort.sort().descending("dateTime"))
                .group(Group.group(Group.id("$stockExchangeCompany")).field("latestStatistics", AccumulatorExpressions.first(Expressions.field("$$ROOT"))))
                .replaceRoot(ReplaceRoot.replaceRoot().field("newRoot", Expressions.field("latestStatistics")))
                .sort(dev.morphia.aggregation.experimental.stages.Sort.sort().ascending("stockExchangeCompany"))
                .skip(10)
                .limit(10)
                .execute(StockExchangeCompanySentimentStatistics.class)
                .toList();

Unfortunately the java code delivers entries with null values on the properties. What exactly is missing?
Technically I want the latest statistics (unique by stockExchangeCompany) with latest dateTime per each company (limited to H1 period).

Second question:

In a non-fluent way I'm also able to retrieve the data but how can I retrieve the real object reference when Morphia gives me a DBRef object? I don't want to have a extra call to the db in order to manually resolve DBRef to real object:

        AggregateIterable<Document> aggregate = datastore.getDatabase().getCollection("stock_exchange_companies_sentiment_statistics")
                .aggregate(Arrays.<Bson>asList(
                        new BasicDBObject("$match", new BasicDBObject("period", "H1")),
                        new BasicDBObject("$sort", new BasicDBObject("dateTime", -1)),
                        new BasicDBObject("$group", new BasicDBObject("_id", "$stockExchangeCompany").append("latestStatistics", new BasicDBObject("$first", "$$ROOT"))),
                        new BasicDBObject("$replaceRoot", new BasicDBObject("newRoot", "$latestStatistics")),
                        new BasicDBObject("$sort", new BasicDBObject("stockExchangeCompany", 1)),
                        new BasicDBObject("$skip", 10),
                        new BasicDBObject("$limit", 10)
                ));

        List<StockExchangeCompanySentimentStatistics> documents = new ArrayList<>();

        for (Document document : aggregate) {
            documents.add(StockExchangeCompanySentimentStatistics.builder()
                    .id(document.getString("id"))
             fails here->       .stockExchangeCompany(document.get("stockExchangeCompany", StockExchangeCompany.class))
                    .build());
        }

EDIT: second question partly resolved via $lookup usage:
new BasicDBObject("$lookup", new BasicDBObject("from", "stock_exchange_companies").append("localField", "stockExchangeCompany.$id").append("foreignField", "_id").append("as", "stockExchangeCompany"))

Is there an elegant Morphia based solution to map a Bson Document directly to the corresponding Entity class?
Right now I use manual getter/setter access and experiment with ModelMapper Framework.

Hope you can help me.

Server Version: 6.0.1 CE
Driver Version: 4.6.1
Morphia Version: 2.2.8

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions