春季 MongoDB 查询文档,如果天差为 x 天

我有一个包含两个日期字段的集合,我正在尝试查询差异为 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

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

答案 1

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

您可以创建 json 查询并将其直接传递为$expr春季在常规查询中尚不受支持。

15 天 = 15 * 24 * 60 * 60 * 1000 = 1296000000 millis

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

3.4 版本

如果你喜欢使用spring mongo方法,你必须使用投影来添加新字段,该字段包含比较,然后是匹配操作和额外的投影以删除比较字段。不幸的是,$addFields仍然不受支持,因此您必须使用 手动创建新阶段。AggregationOperation

AggregationOperation addFields = new AggregationOperation() {
    @Override
    public Document toDocument(AggregationOperationContext aggregationOperationContext) {
        Document document = new Document("comp", Document.parse("{'$gte':[{'$subtract':[{'$ifNull':['$acceptedDate', {'$date':" + System.currentTimeMillis() + "}]},'$lastVisit']},1296000000]}}"));      
        return new Document("$addFields", document);
    }
};

Aggregation aggregation = Aggregation.newAggregation(
        addFields,
        Aggregation.match(Criteria.where("comp").is(true))
        Aggregation.project().andExclude("comp");
);

List<Document> results = mongoTemplate.aggregate(aggregation, collection name, Document.class).getMappedResults();

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();

答案 2

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

  • $ifNull- 如果接受的日期为空,则设置当前日期
  • $addFields- 添加字段,并将现有文档添加到fromfromDaystoDays
  • 过滤器$redact
  • $redact- 在字段和过滤器内匹配
  • $project- 排除阶段中添加的字段$addFields

mongo query

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 聚合查询转换为春季 mongodb 查询