我在一个Spring应用程序中使用MongoDB执行以下搜索:

import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

private CampaignEntity incrByWithConversionRate(ObjectId campaignId, String key) {
    Query query = new Query();
    query.addCriteria(Criteria.where("id").is(campaignId));

    Update update = new Update();
    update.inc(key);
    update.set("conversionRate", new Document("$divide", Arrays.asList("$clicks", "$views")));

    return mongoTemplate.findAndModify(
        query, update,
        new FindAndModifyOptions().returnNew(true), CampaignEntity.class);
}

问题是它失败了,错误如下:

org.springframework.data.mapping.MappingException: Expected to read Document Document{{$divide=[$clicks, $views]}} into type class java.lang.Float but didn't find a PersistentEntity for the latter!

注意:CampaignEntity类的定义如下:

@Data
@Document(collection = "campaigns")
public abstract class CampaignEntity extends BaseEntity {
    private Integer clicks = 0;
    private Integer views = 0;
    private Float conversionRate;
}

推荐答案

我最终使用了以下解决方案:

MnoCampaignEntity campaign = new MnoCampaignEntity();
campaign.setClicks(29);
campaign.setViews(5);
campaignRepository.save(campaign);

String query1 = "{$match: {_id: ObjectId(\"" + campaign.getId() + "\")}}";
String query2 = "{$project: {views: 1, clicks: {$add: [\"$clicks\", 1]}}}";
String query3 = "{$project: {views: 1, clicks: 1, conversionRate: {$cond: [{$eq: [\"$views\", 0]}, 0, {$divide: [\"$clicks\", \"$views\"]}]}}}";
String query4 = "{$merge: \"campaigns\"}";

TypedAggregation<MnoCampaignEntity> aggregation = Aggregation.newAggregation(
    MnoCampaignEntity.class,
    new CustomAggregationOperation(query1),
    new CustomAggregationOperation(query2),
    new CustomAggregationOperation(query3),
    new CustomAggregationOperation(query4)
);

mongoTemplate.aggregate(aggregation.withOptions(new AggregationOptions.Builder()
    .skipOutput()
    .allowDiskUse(true)
    .build()),
    "campaigns", MnoCampaignEntity.class);

CampaignEntity updated = campaignService.findById(campaign.getId().toString());
System.out.println("CONVERSION RATE: " + updated.getConversionRate());

注意:CustomAggregationOperation类从this SO answer开始.

Java相关问答推荐

为什么如果数组列表中有重复项,我的代码SOMETIMES不返回true?

无法初始化JPA实体管理器工厂:无法确定为Java类型<;类>;推荐的JdbcType

查找剩余的枚举

有没有办法让扩展变得多态?

解释左移在Java中的工作原理

Mac上的全屏截图在使用JavaFX时不能正常工作吗?

JOOQ中的子查询使用的是默认方言,而不是配置的方言

如何在Spring Java中从数据库列中获取JSON中的具体数据

MySQL数据库中未应用具有Spring数据的唯一约束

如何在EXCEL单元格中添加形状和文本

在Eclipse中数组的可空性

try 使用Spring集成和MySQL实现发件箱模式时,锁定等待超时

为什么有两种实现来检索数组类的组件类型?

AbstractList保证溢出到其他方法

JavaFX标签中的奇怪字符

如何在Record Java中使用isRecord()和RecordComponent[]?

Win32函数的JNA绑定DwmGetColorizationColor返回E_INVALIDARG错误

如何利用OpenTelemeter将初始值(零)输出到普罗米修斯

如何使JOOQ渐变脚本不重新创建表未更改的类?

如何在java中从以百分比表示的经过时间和结束日期中找到开始日期