当前位置: 首页 > 知识库问答 >
问题:

MongoDB:计算每次状态值更改之间的停留时间

陶高峯
2023-03-14

我想找出每个存在状态变化之间的停留时间。

示例集合-

   /* 1 */

{
    "_id" : ObjectId("5e4889a7c7959f6a13039902"),
    "presenceStatus" : 0,
    "createdAt" : ISODate("2020-02-16T00:14:35.121Z"),
    "updatedAt" : ISODate("2020-02-16T00:14:35.121Z"),
    "__v" : 0
}
/* 2 */
{
    "_id" : ObjectId("5e4889a7c7959f6a1303990c"),
    "presenceStatus" : 1,
    "createdAt" : ISODate("2020-02-16T00:15:35.121Z"),
    "updatedAt" : ISODate("2020-02-16T00:15:35.121Z"),
    "__v" : 0
}
/* 3 */

{
    "_id" : ObjectId("5e4889a9c7959f6a1303995c"),
    "presenceStatus" : 1,
    "sensingTime" : ISODate("2020-02-16T00:15:37.000Z"),
    "createdAt" : ISODate("2020-02-16T00:15:37.420Z"),
    "updatedAt" : ISODate("2020-02-16T00:15:37.420Z"),
    "__v" : 0
}

/* 4 */
{
    "_id" : ObjectId("5e4889b0c7959f6a130399ff"),
    "presenceStatus" : 1,
    "createdAt" : ISODate("2020-02-16T00:15:44.316Z"),
    "updatedAt" : ISODate("2020-02-16T00:15:44.316Z"),
    "__v" : 0
}

/* 5 */
{
    "_id" : ObjectId("5e4889b3c7959f6a13039a58"),
    "presenceStatus" : 1,
    "sensingTime" : ISODate("2020-02-16T00:15:47.000Z"),
    "createdAt" : ISODate("2020-02-16T00:15:47.181Z"),
    "updatedAt" : ISODate("2020-02-16T00:15:47.181Z"),
    "__v" : 0
}

/* 6 */
{
    "_id" : ObjectId("5e4889b5c7959f6a13039aad"),
    "presenceStatus" : 1,
    "sensingTime" : ISODate("2020-02-16T00:15:49.000Z"),
    "createdAt" : ISODate("2020-02-16T00:15:49.545Z"),
    "updatedAt" : ISODate("2020-02-16T00:15:49.545Z"),
    "__v" : 0
}

/* 7 */
{
    "_id" : ObjectId("5e4889b9c7959f6a13039b28"),
    "presenceStatus" : 1,
    "sensingTime" : ISODate("2020-02-16T00:15:53.000Z"),
    "createdAt" : ISODate("2020-02-16T00:15:53.389Z"),
    "updatedAt" : ISODate("2020-02-16T00:15:53.389Z"),
    "__v" : 0
}

/* 8 */
{
    "_id" : ObjectId("5e4889bcc7959f6a13039b78"),
    "presenceStatus" : 1,
    "sensingTime" : ISODate("2020-02-16T00:15:56.000Z"),
    "createdAt" : ISODate("2020-02-16T00:15:56.007Z"),
    "updatedAt" : ISODate("2020-02-16T00:15:56.007Z"),
    "__v" : 0
}

/* 9 */
{
    "_id" : ObjectId("5e4889bfc7959f6a13039c00"),
    "presenceStatus" : 1,
    "sensingTime" : ISODate("2020-02-16T00:15:59.000Z"),
    "createdAt" : ISODate("2020-02-16T00:15:59.619Z"),
    "updatedAt" : ISODate("2020-02-16T00:15:59.619Z"),
    "__v" : 0
}
/* 10 */
{
    "_id" : ObjectId("5e4889c2c7959f6a13039c4a"),
    "presenceStatus" : 0,
    "sensingTime" : ISODate("2020-02-16T00:16:02.000Z"),
    "createdAt" : ISODate("2020-02-16T00:16:02.100Z"),
    "updatedAt" : ISODate("2020-02-16T00:16:02.100Z"),
    "__v" : 0
}

如您所见,第二个文档中的presencestatus从值0更改为1。

我想在状态保持为1时记录此停留时间段。(基本上状态=1到状态=0之间的时差)

当再次找到presenceStatus 1并记录该数据块的presenceStatus保持为1的时间段时,相同的过程将再次启动。

结果集合如下所示-

{
    "_id" : xxx
    "occupiedTime" : ISODate("2020-02-16T00:15:35.121Z"), //  *updatedAt* value of document 2, cause that's when it changed to 1. 

    "vacantTime" : ISODate("2020-02-16T00:16:02.100Z"), // *updatedAt* of document 10, because that's when status changed from 0 to 1. 
    "dwellTime" : (vacant time - occupied time in HH:MM:SS)
    "created" : "2019-05-29 07:08:13",
    "__v" : 0
}

感谢你的帮助。

共有3个答案

南门飞
2023-03-14

您可以在集合上使用Map Reduce,这将以秒为单位输出差异,但在您的端应该相对容易更改。

我没有在任何大型集合上使用过此方法,最近也没有使用过,因此我不知道以这种方式进行此操作对性能的影响,请参阅文档以了解更多信息。

db.collection.mapReduce(
  function() {
    emit(0, this);
  },
  function(key,values){
    var state = values[0].presenceStatus;
    var stateTimestamp = values[0].updatedAt;
    var result = {
      changes: []
    };

    for (var i = 1; i < values.length; i++){
      var value = values[i];
      if (value.presenceStatus !== state) {
        if (state === 1) {
          result.changes.push({
            "dwellTime": value.updatedAt - stateTimestamp,
            "occupiedTime": value.updatedAt,
          });
        }

        state = value.presenceStatus;
        stateTimestamp = value.updatedAt;
      }
    }

    return result;
  },
  {
    out: { inline: 1 }
  }
).results[0].value.changes;
[
        {
                "dwellTime" : 26979,
                "occupiedTime" : ISODate("2020-02-16T00:16:02.100Z")
        }
]
欧阳德运
2023-03-14

@Valijon,@Plancke感谢所有帮助过他的人。我们选择了一种不同的方法,并将我们的“简单for”循环转换为现在能够完成这项工作。再次感谢。如果有人感兴趣,以下是最终解决方案

let prevSensingResults = {}; 

db.sensingresults.find({updatedAt : {$gt :"",$lte : "")}, presenceStatus : {$exists: 1}}).sort({updatedAt:1})
.forEach(function(doc) { 
    if (typeof prevSensingResults[doc.deviceId.toString()] !== undefined) {
         if (prevSensingResults[doc.deviceId.toString()].presenceStatus !== doc.presenceStatus && doc.presenceStatus === 0) {
             db.presenceagg.update({accountId: doc.accountId, buildingId: doc.buildingId, gatewayId: doc.gatewayId, deviceId: doc.deviceId, occupiedTime: prevSensingResults[doc.deviceId.toString()].updatedAt, vacantTime: doc.updatedAt}
         , {accountId: doc.accountId, buildingId: doc.buildingId, gatewayId: doc.gatewayId, deviceId: doc.deviceId, occupiedTime: prevSensingResults[doc.deviceId.toString()].updatedAt, vacantTime: doc.updatedAt, dwellPeriodInSeconds: (doc.updatedAt.getTime() - prevSensingResults[doc.deviceId.toString()].updatedAt.getTime()) / 1000}
                 , {upsert:true});
            prevSensingResults[doc.deviceId.toString()] = doc;
         } else if (prevSensingResults[doc.deviceId.toString()].presenceStatus !== doc.presenceStatus && doc.presenceStatus === 1) 
            prevSensingResults[doc.deviceId.toString()] = doc;
      }
    } else {
        prevSensingResults[doc.deviceId.toString()] = doc;
   }
})
陈瀚玥
2023-03-14

检查此解决方案是否满足您的要求。

  1. 我们加入了同一个系列。因此,对于每个项目,我们取项目1。此方法提供了更改的位置
  2. 我们过滤文档i i 1对,其中presenceStatus是0-1或1-0
  3. 我们将它们分组为单个数据数组
  4. 现在,我们通过两个步骤迭代数据(i=0;i
    var occupiedTime = data[i].tmp.updatedAt
    var vacantTime   = data[i+1].tmp.updatedAt
db.collection.aggregate([
  {
    $lookup: {
      from: "collection",
      let: {
        root_id: "$_id"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $gt: [
                "$_id",
                "$$root_id"
              ]
            }
          }
        },
        {
          $limit: 1
        }
      ],
      as: "tmp"
    }
  },
  {
    $match: {
      $or: [
        {
          "presenceStatus": 1,
          "tmp.presenceStatus": 0
        },
        {
          "presenceStatus": 0,
          "tmp.presenceStatus": 1
        }
      ]
    }
  },
  {
    $group: {
      _id: null,
      data: {
        $push: {
          $mergeObjects: [
            "$$ROOT",
            {
              tmp: {
                $arrayElemAt: [
                  "$tmp",
                  0
                ]
              }
            }
          ]
        }
      }
    }
  },
  {
    $addFields: {
      data: {
        $map: {
          input: {
            $range: [
              0,
              {
                $size: "$data"
              },
              2
            ]
          },
          as: "idx",
          in: {
            "occupiedTime": {
              $arrayElemAt: [
                "$data.tmp.updatedAt",
                {
                  $cond: [
                    {
                      $eq: [
                        {
                          $arrayElemAt: [
                            "$data.tmp.presenceStatus",
                            "$$idx"
                          ]
                        },
                        1
                      ]
                    },
                    "$$idx",
                    {
                      $add: [
                        "$$idx",
                        1
                      ]
                    }
                  ]
                }
              ]
            },
            "vacantTime": {
              $arrayElemAt: [
                "$data.tmp.updatedAt",
                {
                  $cond: [
                    {
                      $eq: [
                        {
                          $arrayElemAt: [
                            "$data.tmp.presenceStatus",
                            "$$idx"
                          ]
                        },
                        0
                      ]
                    },
                    "$$idx",
                    {
                      $add: [
                        "$$idx",
                        1
                      ]
                    }
                  ]
                }
              ]
            },
            "created": {
              $arrayElemAt: [
                "$data.tmp.createdAt",
                "$$idx"
              ]
            },
            "_id": {
              $arrayElemAt: [
                "$data.tmp._id",
                "$$idx"
              ]
            },
            "__v": 0
          }
        }
      }
    }
  },
  {
    $unwind: "$data"
  },
  {
    $replaceRoot: {
      newRoot: "$data"
    }
  },
  {
    $addFields: {
      "dwellTime": {
        $dateToString: {
          date: {
            $toDate: {
              $subtract: [
                "$vacantTime",
                "$occupiedTime"
              ]
            }
          },
          format: "%H-%M-%S"
        }
      }
    }
  }
])

MongoPlayground

 类似资料:
  • 问题内容: 对于单个项目,我想知道在滚动时间内更改的代码行数。 我们正在使用Jenkins和Java,并且我正在寻找某种Jenkins插件或报告,以根据需要提供报告。 目的是确定发现的错误与更改的代码行数之间是否存在关系,更重要的是,要在不同项目之间进行此比较。 问题答案: 我不确定我是否正确理解您的问题,但这是一个主意: 编写一个脚本,该脚本将列出SCM检出中的更改并创建一个文件。添加构建步骤以

  • 问题内容: 我试图找到最干净/最pythonic的方式来评估“ now”是否介于两次之间;然而; 例如,“开始/结束时间”可能会跨越一天的边界,也可能不会跨越一天的边界(仅使用简单的示例): 做一个简单的方案是行不通的! 我目前拥有的一些代码可以评估当前是否为“ NightTime”,如下所示: 我注意到,这些似乎并不能说明开始时间和结束时间跨越一天的边界。 除此之外; 关于添加基于日程安排的任何

  • 我在计算两次约会的时差。。 上面的方法很有效,但它可以提供几天、几小时和几秒钟的时间。我希望它也能告诉我月份。但问题是每个月都有不同的天数,所以我如何才能找到月数呢?

  • 我在python上写了一个小脚本,它从控制台调用命令行来Hibernatelinux机器(或者在一个单词被更改的情况下关闭自己),然后过一段时间醒来。该命令通过watch命令一次又一次地调用。 因此,在PC再次炒起20秒后再次调用rtcwake命令。我希望每次计算机唤醒时都运行另一个脚本。我已经有这个其他脚本,这是一个倒计时。我想这样做是为了向用户显示计算机再次关闭之前还剩下多少时间,但是每次计算

  • 很可能是一个新手的问题,因为我对Android开发相当陌生——我在配置更改/导航时在我的@Composable中保存AndroidView的状态时遇到了麻烦,因为factory block被调用(如预期的那样)并且我的图表被重新实例化。 是一个具有复杂图表的第三方组件,我想保留缩放/滚动状态。我知道我可以使用ViewModel跨配置更改保存UI状态,但考虑到保存缩放/滚动状态的复杂性,我想问一下是

  • 问题内容: 我有一条流经多个系统的消息,每个系统都会记录消息的进入和退出以及时间戳和uuid messageId。我通过以下方式提取所有日志: 结果,我现在有以下事件: 我想生成一个报告(最好是堆积的条或列),用于每个系统的时间: 做这个的最好方式是什么?Logstash过滤器?kibana计算字段? 问题答案: 您只能使用Logstash 过滤器来实现此目的,但是,您必须实质性地重新实现该过滤器