Spring MongoDB 天数相差x天查询文档
Spring MongoDB query documents if days difference is x days
我有一个包含两个日期字段的集合,我正在尝试查询相差 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
- 如果接受日期为空则设置当前日期
$addFields
- 将字段 from
、fromDays
和 toDays
添加到现有文档到
- 过滤器
$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 在常规查询中尚不支持 $expr
。
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.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();
我有一个包含两个日期字段的集合,我正在尝试查询相差 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
- 如果接受日期为空则设置当前日期$addFields
- 将字段from
、fromDays
和toDays
添加到现有文档到- 过滤器
$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 在常规查询中尚不支持 $expr
。
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.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();