广告
返回顶部
首页 > 资讯 > 数据库 >MongoDB时间戳转日期及日期分组实例代码
  • 143
分享到

MongoDB时间戳转日期及日期分组实例代码

mongodb时间戳转时间mongodb时间戳mongodb日期分组 2023-05-16 10:05:00 143人浏览 独家记忆
摘要

目录前言1、日期筛选2、日期转换3、日期分组4、日期排序补充:解决mongoDB存储时间时差的问题总结前言 最近遇到的一个数据统计折线图的性能优化点,可以说是一定思维上的转变,就记录下咯 背景:cron定时任务读取当前统

前言

最近遇到的一个数据统计折线图的性能优化点,可以说是一定思维上的转变,就记录下咯

背景:cron定时任务读取当前统计数据的异常值,频率为每五分钟记录一次,折线图要求获取每日的异常项峰值

最一开始的想法:将数据读取到内存中进行条件过滤、计算

首先根据时间戳将数据以日期作为分组,其次在每个分组中获取异常项的峰值数据,时间复杂度O(n*n),最好以日期分组列表+峰值数据列表作为对象返回结果

遇到性能问题:一天的数据量为(60/5)*24=288,默认日期为15天,则统计的数据量为4230,接口返回甚至需要8、9秒的时间,作为一个项目的门面折线图,这种情况 达咩!

优化的念头:我要拿每天的峰值数据,怎么才能直接取到每天的峰值呢,monGo的聚合是不是可以做到啊? $group可以按日期做分组, $max可以拿到最大值,接下来一个 $sort好像是就成了吧! 说干就干!!

接下来的聚合语句均为mongo pipeline,最后附上golang的bson条件哈

// ResultCountModel _
type ResultCountModel struct {
	CommonBase `JSON:",inline" yaml:",inline" bson:",inline"`
	ErrorCount int   `json:"error_count" bson:"error_count"`
	Timestamp  int64 `json:"timestamp" bson:"timestamp"`
	MaxTime    int64 `json:"max_time" bson:"max_time"`
}

数据结构定义如上,这里使用CommonBase,是因为在$group聚合后会得到_id唯一标识字段,因此便于获取最后的聚合结果,在定义结构体时将其加上;timestamp单位为毫秒

1、日期筛选

第一步,毫无疑问,对时间戳timestamp进行日期的过滤

  {
    $match: {
        timestamp: {
            $gte: 1671897600000, // min_timestamp
            $lt: 1673280000000   // max_timestamp
        }
    }
  }
  • $gte 大于等于
  • $lt 小于

2、日期转换

第二步,根据时间戳大小进行日期的转换,这里是用的是$project, 将具有请求字段的文档传递到管道中的下一阶段。指定的字段可以是输入文档中的现有字段或是新计算的字段

使用$project主要思路是,将timestamp时间戳转换为标准日期,之后输出为想要的fORMat形式;同时使用 $project保留需要的字段

时间戳转换日期

核心方法:$dateToString

{ 
  $dateToString: {
    date: <dateExpression>,
    format: <formatString>,
    timezone: <tzExpression>,
    onNull: <expression>
  }
}
  • date :要转换的字符串日期,必须是解析为Date、Timestamp、ObjectID 的有效表达式
  • format: 日期格式规范
  • timezone:运算结果的时区,常用UTC偏移量
  • onNull: date为null或缺失时要返回的值

日期格式想要“月份-日期”,那format: “%m-%d”

日期数据这里,如果直接使用输入文档中的现有字段的话 date: “$timestamp”,则会报错:PlanExecutor error during aggregation :: caused by :: can’t convert from BSON type long to Date

因此我们需要将时间戳转换为日期: 即格林威治开始时间(1970-01-01 00:00:00)+时间戳+时差

  date:{
    $add:[
      new Date(0),
      "$timestamp",
      28800000
    ]
  },

注意⚠️:

  • MongoDB时间的基本单位为毫秒,所以本文直接使用”$timestamp”即可;若时间单位为秒级时,则需要使用 $multiply进行乘法运算:{ $multiply:[" $timestamp”,1000]}
  • MongoDB是UTC时区,即中时区(0度经线), 中国为东八区,因此需要使用timezone添加8小时(即28800000毫秒)

pipeline如下:

  day:{
    $dateToString:{
      format:"%m-%d",
      date:{
        $add:[
          new Date(0),
          "$timestamp",
          28800000
        ]
      },
    }
  },

保留需要字段


{
  timestamp:1,
  error_count:1,
}

$project将保留字段置为1即可进行数据保留操作

第二步完整pipeline如下:

{
    $project: {
        day: {
            $dateToString: {
                format: '%m-%d',
                date: {
                    $add: [
                        ISODate('1970-01-01T00:00:00.000Z'),
                        '$timestamp',
                        28800000
                    ]
                }
            }
        },
        timestamp: 1,
        error_count: 1
    }
},

3、日期分组

第三步,使用$group进行日期分组

{
  $group:
    {
      _id: <expression>, // Group key
      <field1>: { <accumulator1> : <expression1> },
      ...
    }
 }
  • _id: 表达式指定组密钥
  • field: 计算使用的累加器运算符

这里我们需要将第二步获得的日期转换进行分组聚合,同时获取每个分组的异常项最大值即峰值数据

{
    $group: {
        _id: '$day',
        error_count: {
            $max: '$error_count'
        },
        max_time: {
            $max: '$timestamp'
        }
    }
}, 

这里额外获取了max_time字段,主要用于在计算统计数据时的排序,在最后排序部分会使用到

4、日期排序

这里做一个假设,如果不使用max_time的话,如何将数据进行按日期的排序呢? 如果根据_id进行排序,则会出现“上年末”排序在“下年初”的情况(感谢现在的,不然会忘记这个问题)

所以将每个分组的最大时间戳保留下来时很有必要的!

这里取$max $min都是可以的哈

{
    $sort: {
        max_time: 1
    }
}

最终完整pipeline:

[{
 $match: {
  timestamp: {
   $gte: 1671897600000,
   $lt: 1673280000000
  }
 }
}, {
 $project: {
  day: {
   $dateToString: {
    format: '%m-%d',
    date: {
     $add: [
      ISODate('1970-01-01T00:00:00.000Z'),
      '$timestamp',
      28800000
     ]
    }
   }
  },
  timestamp: 1,
  error_count: 1
 }
}, {
 $group: {
  _id: '$day',
  error_count: {
   $max: '$error_count'
  },
  max_time: {
   $max: '$timestamp'
  }
 }
}, {
 $sort: {
  max_time: 1
 }
}]
[{
 $match: {
  timestamp: {
   $gte: 1671897600000,
   $lt: 1673280000000
  }
 }
}, {
 $project: {
  day: {
   $dateToString: {
    format: '%m-%d',
    date: {
     $add: [
      ISODate('1970-01-01T00:00:00.000Z'),
      '$timestamp',
      28800000
     ]
    }
   }
  },
  timestamp: 1,
  error_count: 1
 }
}, {
 $group: {
  _id: '$day',
  error_count: {
   $max: '$error_count'
  },
  max_time: {
   $max: '$timestamp'
  }
 }
}, {
 $sort: {
  max_time: 1
 }
}]

golang里面,Aggregate则直接使用pipeline即可,亦可转换为filter使用

filter代码:

filter := bson.A{
		bson.D{{"$match", bson.D{
			{"timestamp", bson.D{
				{"$gte", param.MinTimestamp},
				{"$lt", param.MaxTimestamp},
			}}}},
		},
		bson.D{{"$project", bson.D{
			{"day", bson.D{
				{"$dateToString", bson.D{
					{"format", "%m-%d"},
					{"date", bson.D{
						{"$add", bson.A{
							time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
							"$timestamp",
							28800000,
						}},
					}},
				}},
			}},
			{"error_count", 1},
			{"timestamp", 1},
		}}},
		bson.D{{"$group", bson.D{
			{"_id", "$day"},
			{"max_time", bson.D{{"$max", "$timestamp"}}},
			{"error_count", bson.D{{"$max", "$error_count"}}},
		}}},
		bson.D{{"$sort", bson.D{{"max_time", 1}}}},
	}

完结撒花

补充:解决MongoDB存储时间时差的问题

MongoDB存储时间类型数据时,都是先转换为UTC时间,然后存储到数据库中,当我们取出存储的时间时,就会出现时差的问题。比如我们用的北京时间,读取到的数值就会看到比当前时间少了8个小时,难道说我们在每次读取的时候都要单独处理一下时间吗,这就比较麻烦。其实,我们可以在存储的时候进行相应的处理,只需使用getTimezoneOffset()和toISOString()函数。

getTimezoneOffset函数:返回此地区的时差(当地时间与GMT格林威治标准时间的地区时差),单位为分钟。

<script>
  // 我们是东八区
  var d = new Date();
  var tz = d.getTimezoneOffset();
  console.log(tz);  // -480
</script>

toISOString()函数:使用ISO标准将 Date 对象转换为字符串。

该标准称为 ISO-8601 ,格式为: YYYY-MM-DDTHH:mm:ss.sssZ。

封装时间转换函数

localDate(v) {
    const d = new Date(v || Date.now());
    d.setMinutes(d.getMinutes() - d.getTimezoneOffset());
    return d.toISOString();
},

我们在存储时间的时候调用localDate()这个函数就可以了,无论你处在哪个时区结果显示都和当地时间一样。

总结

到此这篇关于MongoDB时间戳转日期及日期分组的文章就介绍到这了,更多相关MongoDB时间戳转日期内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

您可能感兴趣的文档:

--结束END--

本文标题: MongoDB时间戳转日期及日期分组实例代码

本文链接: https://www.lsjlt.com/news/209531.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • MongoDB时间戳转日期及日期分组实例代码
    目录前言1、日期筛选2、日期转换3、日期分组4、日期排序补充:解决MongoDB存储时间时差的问题总结前言 最近遇到的一个数据统计折线图的性能优化点,可以说是一定思维上的转变,就记录下咯 背景:cron定时任务读取当前统...
    99+
    2023-05-16
    mongodb时间戳转时间 mongodb 时间戳 mongodb 日期分组
  • JavaScript实现日期时间转时间戳
    目录1、date.getTime()2、date.valueOf()3、Date.parse(date)4.时间戳转年月日时分秒5.当前时间往前推30天、7天、3天6.获取最近七天日...
    99+
    2022-11-13
  • Mongodb 如何将时间戳转换为年月日日期
    目录MongoDB将时间戳转换为年月日日期MongoDB中的日期查询的坑Mongodb将时间戳转换为年月日日期 使用dateToString 方法进行转换 并且通过format指定转换日期格式 Integer u...
    99+
    2022-10-17
  • Mongodb如何将时间戳转换为年月日日期
    目录Mongodb将时间戳转换为年月日日期MongoDB中的日期查询的坑Mongodb将时间戳转换为年月日日期 使用dateToString 方法进行转换 并且通过format指定转...
    99+
    2022-11-13
    Mongodb时间戳 时间戳转换日期 时间戳转换年月日日期
  • MongoDB中怎么将时间戳转为日期格式
    这篇文章给大家介绍MongoDB中怎么将时间戳转为日期格式,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。MongoDB模糊查询方法示例:模糊查询:tname包含某个关键字测试'...
    99+
    2022-10-18
  • clickhouse时间戳转换日期怎么实现
    在ClickHouse中,可以使用toDate函数将时间戳转换为日期。toDate函数的语法如下: toDate(timestamp...
    99+
    2023-10-23
    clickhouse
  • php实现日期转unix时间戳的方法
    本文将为大家详细介绍“php实现日期转unix时间戳的方法”,内容步骤清晰详细,细节处理妥当,而小编每天都会更新不同的知识点,希望这篇“php实现日期转unix时间戳的方法”能够给你意想不到的收获,请大家跟着小编的思路慢慢深入,具体内容如下...
    99+
    2023-06-06
  • php怎么实现日期和时间戳的转换
    PHP是一种流行而强大的编程语言,拥有广泛的应用。其中,日期与时间戳(timestamp)的转换也是开发者们经常需要处理的问题。本文将介绍如何将PHP中的日期转换成时间戳,以及如何将时间戳转换成日期。将日期转换成时间戳在PHP中,我们可以通...
    99+
    2023-05-14
    php时间戳 php
  • php如何实现日期和时间戳的转换
    这篇文章主要介绍“php如何实现日期和时间戳的转换”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“php如何实现日期和时间戳的转换”文章能帮助大家解决问题。将日期转换成时间戳在PHP中,我们可以通过内...
    99+
    2023-07-05
  • 怎么使用PHP时间戳转换源码来转换时间戳为日期格式
    这篇“怎么使用PHP时间戳转换源码来转换时间戳为日期格式”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么使用PHP时间戳转...
    99+
    2023-07-05
  • JavaScript怎么实现两个时间戳之间转换成日期数组
    这篇文章主要介绍了JavaScript怎么实现两个时间戳之间转换成日期数组的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JavaScript怎么实现两个时间戳之间转换成日期数组...
    99+
    2022-10-19
  • JavaScript内置日期、时间格式化时间实例代码
    一、基础知识(date对象的方法) 😜 getFullYear( ) 用于返回一个表示年份的4位数 🤣 getMonth( ) 返回表示月份的数字,...
    99+
    2022-11-12
  • MySQL 日期时间加减的示例代码
    目录1.MySQL加减某个时间间隔2.日期相减最近在复习MySQL,正好看到了MySQL 日期时间,本文就给自己留个笔记,顺便分享给大家 now (); 当前具体的日期和时...
    99+
    2022-11-12
  • Mysql查询时间区间日期列表实例代码
    目录1、查询时间区间日期列表,不会由于数据表数据影响2、创建视图可以公共使用3、创建为视图之后,可以通过视图查询时间区间列表日期4、查询时间区间按月附:在对mysql的时间进行区间查...
    99+
    2022-11-13
  • javascript实现日期转成时间戳的方法是什么
    本篇内容介绍了“javascript实现日期转成时间戳的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有...
    99+
    2022-10-19
  • php如何实现时间戳转日期并使月份去0
    小编给大家分享一下php如何实现时间戳转日期并使月份去0,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!php时间戳转日期并使月份去0的实现方法:首先创建一个PHP...
    99+
    2023-06-20
  • Android开发中DatePicker日期与时间控件实例代码
    一、简介二、方法最日常的使用方法了日期控件DatePicker时间控件TimePicker月份从0开始三、代码实例效果图:代码:fry.Activity01package fry;import com.example.DatePicherD...
    99+
    2023-05-30
    android datepicker dat
  • Dos下日期时间引用的实现代码
    本篇内容主要讲解“Dos下日期时间引用的实现代码”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Dos下日期时间引用的实现代码”吧!%date%输出的是:星期* yyyy/mm/dd (如:星期四...
    99+
    2023-06-08
  • Android开发之时间日期组件用法实例
    继上一篇时间和日期设置的示例之后,今天来介绍Android的布局组件中有关于时间和日期的设置的组件,希望对大家有所帮助。具体如下: 时间日期设置组件:TimePicker、Da...
    99+
    2022-06-06
    时间日期 android开发 Android
  • php时间戳转换实例代码分析
    本文小编为大家详细介绍“php时间戳转换实例代码分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“php时间戳转换实例代码分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一、时间戳的概念Unix时间戳,也叫做...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作