这里是my_task集合的样本记录,当任务状态改变时,将有一条记录添加到status_changed_utc字段中,其中包含状态代码和时间,状态6表示任务已完成;在最顶层还具有requested_completion_utc字段,表示该任务的预期完成时间是多少,那么对于该月创建的任务,我如何找出实际完成时间晚于requested_completion_utc的记录?请注意,记录中可能不存在状态为6的request_completion_utc和status_changed_utc。
样本记录:
formikProps
答案 0 :(得分:1)
我认为可能有一种更有效的编写方法,但是我能够使用聚合框架提出。
Hierarchy
您的文档从上面返回以下内容:
db.tasks.aggregate([
// Only show results with the requested_completion_utc value
{ $match: { requested_completion_utc: { $exists: 1 } } },
// Get only the most recent status change by slicing the last element of the array
{ $project: {
id: 1,
requested_completion_utc: 1,
status_changed_utc: { $slice: [ "$status_changed_utc", -1 ] }
}},
// Perform the comparison to determine if the operation was late
{ $project: {
id: 1,
requested_completion_utc: 1,
status_changed_utc: 1,
isLate: { $gt: [ "$requested_completion_utc", "$status_changed_utc.time" ] },
}},
// Only display the late results
{ $match: { isLate: true } },
]);
请注意,这仅返回最新的“后期”违规者,如果您希望在此之后发生的所有操作,则可以使用$ unwind聚合运算符为status_changed_utc数组中的每个元素而不是$创建一个单独的文档。项目阶段将每个数组的最新元素切片。
答案 1 :(得分:0)
以下汇总查询将返回在5月创建的任务的ID,这些任务的状态为(6),该状态在请求的完成日期之后已完成。希望我能正确理解您的要求。
db.my_task.aggregate([
{
"$match": {
"created_utc": {
"$gt": ISODate("2019-04-30T18:30:00.000Z"),
"$lt": ISODate("2019-05-31T18:30:00.000Z")
},
"status_changed_utc": {
"$elemMatch": {
"status": 6
}
}
}
},
{
"$unwind": "$status_changed_utc"
},
{
"$project": {
"status": "$status_changed_utc.status",
"isLate": {
"$gt": [
"$status_changed_utc.time",
"$requested_completion_utc"
]
},
"_id": 1
}
},
{
"$match": {
"isLate": true,
"status": 6
}
},
{
"$project": {
"_id": 1
}
}
])
如果有人感兴趣,这是生成上述命令的c#代码:
using MongoDB.Entities;
using System;
using System.Linq;
namespace StackOverflow
{
[Name("my_task")]
public class MyTask : Entity
{
public DateTime created_utc { get; set; }
public DateTime requested_completion_utc { get; set; }
public Status[] status_changed_utc { get; set; }
}
public class Status
{
public int status { get; set; }
public DateTime time { get; set; }
}
public static class Program
{
public static void Main()
{
new DB("my_database", "localhost");
var start = new DateTime(2019, 05, 1, 0, 0, 0).ToUniversalTime();
var end = new DateTime(2019, 06, 1, 0, 0, 0).ToUniversalTime();
var result = DB.Queryable<MyTask>()
.Where(t =>
t.created_utc > start &&
t.created_utc < end &&
t.status_changed_utc.Any(s => s.status == 6))
.SelectMany(t => t.status_changed_utc,
(t, s) => new
{
t.ID,
s.status,
isLate = s.time > t.requested_completion_utc
})
.Where(x => x.isLate == true && x.status == 6)
.Select(x => x.ID)
.ToList();
}
}
}
答案 2 :(得分:0)
我有类似的问题。
先排序,然后再投影最新的一个就不能解决我的问题,因为我需要输出多个完成时间。
这是我的问题,除了使用$ unwind函数外,还有其他方法可以处理文档中的此数组吗?
我不想使用$ unwind的原因是要构造一个数组字段以为每个元素输出文档,并且我对查询应用了多个过滤器,这将增加与其他记录匹配的记录总数过滤器。
这是我的样本记录
"_id" : ObjectId("5d9b69fae4757402b4b4ca0d"),
"status_changed_utc" : [
{
"status" : NumberInt(1),
"time" : ISODate("2019-05-20T23:03:10.000+0000")
},
{
"status" : NumberInt(2),
"time" : ISODate("2019-05-23T23:04:03.000+0000")
},
{
"status" : NumberInt(4),
"time" : ISODate("2019-05-23T23:05:06.000+0000")
},
{
"status" : NumberInt(5),
"time" : ISODate("2019-05-23T23:05:07.000+0000")
},
{
"status" : NumberInt(6),
"time" : ISODate("2019-05-23T23:05:09.000+0000")
}
],
"requested_completion_utc" : ISODate("2019-05-22T23:05:09.000+0000")
当我尝试使用此查询时
db.getCollection("test").aggregate(
[
{
"$match" : {
"requested_completion_utc" : {
"$exists" : 1.0
}
}
},
{
"$project" : {
"_id" : 1.0,
"requested_completion_utc" : 1.0,
"status_changed_utc" : {
"$slice" : [
"$status_changed_utc",
-1.0
]
}
}
}
]
它将把这个结果返回给我。
{
"_id" : ObjectId("5d9b69fae4757402b4b4ca0d"),
"requested_completion_utc" : ISODate("2019-05-22T23:05:09.000+0000"),
"status_changed_utc" : [
{
"status" : NumberInt(6),
"time" : ISODate("2019-05-23T23:05:09.000+0000")
}
]
}
是否可以返回状态NumberInt(2)代替对我来说是最新完成状态的NumberInt(6)?
这是我预期的结果
{
"_id" : ObjectId("5d9b69fae4757402b4b4ca0d"),
"requested_completion_utc" : ISODate("2019-05-22T23:05:09.000+0000"),
"status_changed_utc" : [
{
"status" : NumberInt(2),
"time" : ISODate("2019-05-23T23:04:03.000+0000")
}
]
}