Java Spring MongoDB在天数差为x天时查询文档

Java Spring MongoDB在天数差为x天时查询文档,java,mongodb,spring-boot,criteria,spring-data-mongodb,Java,Mongodb,Spring Boot,Criteria,Spring Data Mongodb,我有一个包含两个日期字段的集合,我正在尝试查询所有相差15天的记录: { "_id" : "someid", "factoryNumber" : 123, "factoryName" : "some factory name", "visitType" : "audit", "personelId" : "somePersonel", "lastVisit": ISODate("2018-10-30T00:00:00.000+0000"), "accep

我有一个包含两个日期字段的集合,我正在尝试查询所有相差15天的记录:

{
   "_id" : "someid",
   "factoryNumber" : 123,
   "factoryName" : "some factory name",
   "visitType" : "audit",
   "personelId" : "somePersonel",
   "lastVisit": ISODate("2018-10-30T00:00:00.000+0000"),
   "acceptedDate" : ISODate("2018-11-16T00:00:00.000+0000")
}
现在,在某些情况下,
acceptedDate
将不存在,因此我需要根据当前日期对其进行评估。不完全确定如何在spring中编写此类查询以获得所需的结果

    Criteria.where("acceptedDate"). 
(is 15 days past last visit or current date if last visit not present)

您需要使用聚合管道来获取文档

  • $ifNull
    -如果接受日期为null,则设置当前日期
  • $addFields
    -将字段
    从天
    今天
    添加到现有文档中
  • 过滤
    $redact
  • $redact
    -在字段和筛选器中匹配
  • $project
    -排除在
    $addFields
    阶段中添加的字段
mongo查询

db.t1.aggregate([
    {$addFields : {
        from : {$ifNull : ["$acceptedDate", new Date()]}
    }},
    {$addFields: {
        fromDays : {$sum : [{$multiply : [365, {$year : "$from"}]}, {$dayOfYear : "$from"}]},
        toDays : {$sum : [{$multiply : [365, {$year : "$lastVisit"}]}, {$dayOfYear : "$lastVisit"}]}
    }},
    { $redact: {
        $cond: {
           if: {$lte : [{$subtract : ["$fromDays", "$toDays"]}, 15]},
           then: "$$DESCEND",
           else: "$$PRUNE"
         }
       }
    },
    {$project : {from:0, fromDays:0, toDays:0}}
])
样本采集

> db.t1.find().pretty()
{
        "_id" : "someid",
        "factoryNumber" : 123,
        "factoryName" : "some factory name",
        "visitType" : "audit",
        "personelId" : "somePersonel",
        "lastVisit" : ISODate("2018-10-30T00:00:00Z"),
        "acceptedDate" : ISODate("2018-11-16T00:00:00Z")
}
{
        "_id" : "someotherid",
        "factoryNumber" : 123,
        "factoryName" : "some factory name",
        "visitType" : "audit",
        "personelId" : "somePersonel",
        "lastVisit" : ISODate("2018-10-30T00:00:00Z")
}
至少150天的结果

> db.t1.aggregate([ {$addFields : { from : {$ifNull : ["$acceptedDate", new Date()]} }}, {$addFields: { fromDays : {$sum : [{$multiply : [365, {$year : "$from"}]}, {$dayOfYear : "$from"}]}, toDays : {$sum : [{$multiply : [365, {$year : "$lastVisit"}]}, {$dayOfYear : "$lastVisit"}]} }}, { $redact: {         $cond: {            if: {$lte : [{$subtract : ["$fromDays", "$toDays"]}, 150]},            then: "$$DESCEND",            else: "$$PRUNE"          }        } }, {$project : {from:0, fromDays:0, toDays:0}} ]).pretty()
{
        "_id" : "someid",
        "factoryNumber" : 123,
        "factoryName" : "some factory name",
        "visitType" : "audit",
        "personelId" : "somePersonel",
        "lastVisit" : ISODate("2018-10-30T00:00:00Z"),
        "acceptedDate" : ISODate("2018-11-16T00:00:00Z")
}
{
        "_id" : "someotherid",
        "factoryNumber" : 123,
        "factoryName" : "some factory name",
        "visitType" : "audit",
        "personelId" : "somePersonel",
        "lastVisit" : ISODate("2018-10-30T00:00:00Z")
}
>

将mongo聚合查询转换为spring mongodb查询

从3.6开始,您必须使用新的运算符
$expr
,它允许在匹配查询或常规查询中使用聚合表达式

您可以创建json查询并直接传递它,因为在常规查询中spring还不支持json查询

15天=15*24*60*60*1000=1296000000毫秒

Query query = new BasicQuery("{'$expr':{'$gte':[{'$subtract':[{'$ifNull':['$acceptedDate',{'$date':" + System.currentTimeMillis() + "}]},'$lastVisit']},1296000000]}}");
List<Document> results = mongoTemplate.find(query, Document.class);
3.2版本

AggregationOperation redact = new AggregationOperation() {
    @Override
    public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) {
    Map<String, Object> map = new LinkedHashMap<>();
    map.put("if",  BasicDBObject.parse("{'$gte':[{'$subtract':[{'$ifNull':['$acceptedDate', {'$date':" + System.currentTimeMillis() + "}]},'$lastVisit']},1296000000]}}"));
    map.put("then", "$$KEEP");
    map.put("else", "$$PRUNE");
    return new BasicDBObject("$redact", new BasicDBObject("$cond", map));
};

Aggregation aggregation = Aggregation.newAggregation(redact);

List<FactoryAcceptance> results = mongoTemplate.aggregate(aggregation, FactoryAcceptance.class, FactoryAcceptance.class).getMappedResults();
AggregationOperation编校=新的AggregationOperation(){
@凌驾
公共数据库对象toDBObject(聚合操作上下文聚合操作上下文){
Map Map=newlinkedhashmap();
map.put(“if”,BasicDBObject.parse(“{'$gte':[{'$subtract':[{'$ifNull':['$acceptedDate',{'$date':“+System.currentTimeMillis()+”}]},$lastVisit']},1296000000]}”);
map.put(“then”,“$$KEEP”);
map.put(“else”,“$$PRUNE”);
返回新的BasicDBObject($redact),新的BasicDBObject($cond,map));
};
聚合=聚合。新建聚合(修订);
List results=mongoTemplate.aggregate(聚合,FactoryAcceptance.class,FactoryAcceptance.class).getMappedResults();

nice,我最关心的是spring部分,因为它会产生这个问题+公司范围内目前使用的版本是3.2。我想我不能使用expralso当我重写聚合操作时,它强迫我使用DBObject?与我的集合实体名称相反?更新了3.2版和spring mongo 1.x jar的答案。感谢您提出的一个快速问题,如果我的实体名为FactoryAcceptance,那么我需要将列表映射到我的列表?它会在记录中包含所有字段吗?由于某种原因,我在第一个map.put-basicdbobobject.parse上遇到了一个json解析错误,但对我来说很好
AggregationOperation redact = new AggregationOperation() {
    @Override
    public DBObject toDBObject(AggregationOperationContext aggregationOperationContext) {
    Map<String, Object> map = new LinkedHashMap<>();
    map.put("if",  BasicDBObject.parse("{'$gte':[{'$subtract':[{'$ifNull':['$acceptedDate', {'$date':" + System.currentTimeMillis() + "}]},'$lastVisit']},1296000000]}}"));
    map.put("then", "$$KEEP");
    map.put("else", "$$PRUNE");
    return new BasicDBObject("$redact", new BasicDBObject("$cond", map));
};

Aggregation aggregation = Aggregation.newAggregation(redact);

List<FactoryAcceptance> results = mongoTemplate.aggregate(aggregation, FactoryAcceptance.class, FactoryAcceptance.class).getMappedResults();