MongoDB助力快速搭建物流订单系统
简介
快递物流系统里最常见的一种业务类型就是订单的查询和记录。订单的特点是随着递送过程,订单数据需要随时更新路径。数据结构上需要可以灵活应对,这点非常符合Document模型,并且MongoDB支持GIS功能,非常适用于MongoDB来支撑物流业务。并且MongoDB具备Sharding能力,而物流行业里订单比较独立,夸订单的操作很少,而对单订单来说,更新追加的操作会较多,比如再物流中转处理上。所以物流业务模型上与MongoDB非常的匹配。以下讲解一个虚拟的DEMO,可供参考,用到的特性:
- MongoDB Document的数组结构
- TTL索引,自动过期历史数据
- 复合索引,多条件查询索引
- Partial Indexes,条件索引,只索引有效数据,降低索引的占用空间
- MongoDB GIS功能,支持GeoJSON标准,可以接入第三方系统处理GEO信息。
数据结构定义
{
"_id": <String>, // 订单ID
"status": <String>, // 订单状态,shipping,deliveried等
"order_image_url": <String>, // 订单图片信息
"create_date": <ISODate>, // 订单创建日期
"from": { // 发货信息
"city": <String>, "address": <String>,
"name": <String>, "phone": <String>,
"location": <GeoJSON>
},
"delivery": { // 收货信息
"city": <String>, "address": <String>,
"name": <String>, "phone": <String>,
"location": <GeoJSON>
},
"details": [ // 物流详情,数组结构
{
"action": "reviced", // 物流动作
"operator": "快递小哥1号", // 操作员
"date": <ISODate>
}...
]
}
例如:
{
"_id": "E123456789",
"status": "delivering",
"create_date": ISODate("2016-06-21T09:00:00+08:00"),
"order_image_url": "http://oss/xxxxx.jpg",
"from": {
"city": "Hangzhou",
"address": "文一西路969号",
"name": "小王",
"phone": "18657112345",
"location": {
"type": "Point",
"coordinates": [
120,
30
]
}
},
"delivery": {
"city": "北京",
"address": "朝阳区",
"name": "朝阳群众",
"phone": "18601011011",
"location": {
"type": "Point",
"coordinates": [
116,
39
]
}
},
"details": [
{
"action": "reviced",
"operator": "快递小哥1号",
"date": ISODate("2016-06-21T09:00:00+08:00")
},
{
"action": "shipping",
"station": "hangzhou-airport",
"date": ISODate("2016-06-22T01:00:00+08:00")
},
{
"action": "shipping",
"station": "beijing-airport",
"date": ISODate("2016-06-22T07:00:00+08:00")
},
{
"action": "shipping",
"station": "chaoyang-station",
"date": ISODate("2016-06-22T15:00:00+08:00")
},
{
"action": "delivering",
"operator": "快递小哥2号",
"date": ISODate("2016-06-23T10:00:00+08:00")
}
]
}
几个注意点:
- 利用了GEO特性,使用GeoJSON标准,但是坐标系上需要注意坐标标准问题;
- 时间处理上,物流行业会涉及到国际化,所以严格按照ISO的标准,定义时间,CN
+80:00
; - 订单详情里很好的利用了Document的数组特性;
- 快递订单是唯一的,可以作为MongoDB的主键;
insert到collection中后的文档:
> db.order.find().pretty()
{
"_id" : "E123456789",
"status" : "delivering",
"create_date" : ISODate("2016-06-21T01:00:00Z"),
"order_image_url" : "http://oss/xxxxx.jpg",
"from" : {
"city" : "Hangzhou",
"address" : "文一西路969号",
"name" : "小王",
"phone" : "18657112345",
"location" : {
"type" : "Point",
"coordinates" : [
120,
30
]
}
},
"delivery" : {
"city" : "北京",
"address" : "朝阳区",
"name" : "朝阳群众",
"phone" : "18601011011",
"location" : {
"type" : "Point",
"coordinates" : [
116,
39
]
}
},
"details" : [
{
"action" : "reviced",
"operator" : "快递小哥1号",
"date" : ISODate("2016-06-21T01:00:00Z")
},
{
"action" : "shipping",
"station" : "hangzhou-airport",
"date" : ISODate("2016-06-21T17:00:00Z")
},
{
"action" : "shipping",
"station" : "beijing-airport",
"date" : ISODate("2016-06-21T23:00:00Z")
},
{
"action" : "shipping",
"station" : "chaoyang-station",
"date" : ISODate("2016-06-22T07:00:00Z")
},
{
"action" : "delivering",
"operator" : "快递小哥2号",
"date" : ISODate("2016-06-23T02:00:00Z")
}
]
}
数据操作
物流快递的订单修改主要是查询和信息追加两种,主要介绍这两种:
订单信息查询,最常见的操作,用户的订单查询:
db.order.find({_id:"E123456789"});
有时需要做信息统计,按照状态来查询:
db.order.find({"status":"delivering", "delivery.city":"北京", "delivery.address":"朝阳区"});
物流状态更新时,需要更新相应的订单,MongoDB上直接 $push
过去即可:
db.order.update( { _id:"E123456789"},
{$push: {details:
{"action":"delivering", "operator" : "快递小哥3号", "date" : ISODate("2016-06-23T13:00:00+8:00")}
}})
索引创建
_id
索引,默认存在,不需要再创建;当数据量较大时,可以使用sharding结构,shardkey的选择上可以使用 Hash(_id)
。
TTL索引,字段 create_date
,180天后自动清理数据:
db.order.createIndex({"create_date":1}, {"expireAfterSeconds":15552000})
位置和状态索引,为了能快速处理“某地未处理订单”查询,这是一个多条件的查询,所以是一个复合索引, status
字段放在前面,因为多数的查询都会依赖状态字段
db.order.createIndex({"status":1, "delivery.city":1, "delivery.address":1})
在这个Demo里,还有一种加快查询速度的方法就是,创建一个只包含指定状态的一个Partial Indexes索引。比如 status
必须为 delivering
才加入到索引中,有效控制索引的大小,加快查询速度。
db.order.createIndex({"delivery.city":1, "delivery.address":1},{partialFilterExpression:{'status':{$eq:"delivering"}}})
MongoDB GIS
MongoDB遵循的事GeoJSON规范,对象的描述上通过一个type字段描述GeoJSON类型,coordinates字段描述空间信息。
{ type: "<GeoJSON type>" , coordinates: <coordinates> }
coordinates是一个 [longitude, latitude]
的数组类型。另外值得关注的是MongoDB GEO的使用的是WGS84标准。WGS84也是国际标准,中国使用的著名的火星坐标GCJ-02,还有一套百度坐标BD09,三者的坐标转换可以参考附录相关的链接。
附录
GeoJSON
MongoDB Geo Index
GeoHack
- https://tools.wmflabs.org/geohack/geohack.php?pagename=Hangzhou¶ms=30\_15\_N\_120\_10\_E\_type:city(9018000)_region:CN-33_
- https://tools.wmflabs.org/geohack/geohack.php?pagename=Beijing¶ms=39\_55\_N\_116\_23\_E\_type:city(21700000)_region:CN-11_
- https://en.wikipedia.org/wiki/World\_Geodetic\_System
Geo Datum
MongoDB助力快速搭建物流订单系统的更多相关文章
- SpringBoot+MongoDB实现物流订单系统
码字不易,点赞收藏,养成习惯!原创作者公众号:bigsai.更多精彩期待与您分享!项目收录在github的MongoDB案例中,文章收录在回车课堂中如果没基础请看看前两篇(墙裂推荐)MongoDB从立 ...
- Telegraf+InfluxDB+Grafana快速搭建实时监控系统 监控postgresql
Telegraf+InfluxDB+Grafana快速搭建实时监控系统 监控postgresql
- Django快速搭建博客系统
Django快速搭建博客系统 一.开发环境 Windows 7(64bit) python 3.6 https://www.python.org/ Django 2.0 https://www. ...
- 使用ASP.NET MVC+Entity Framework快速搭建博客系统
学习 ASP.NET MVC 也有一段时间了,打算弄个小程序练练手,做为学习过程中的记录和分享. 首先,得确定需求,木有需求的话,那还搞个毛线呀!嗯……大致思考了一下,终于得出如下需求: 1.能自定义 ...
- 使用ASP.NET MVC+Entity Framework快速搭建系统
详细资料: http://www.cnblogs.com/dingfangbo/p/5771741.html 学习 ASP.NET MVC 也有一段时间了,打算弄个小程序练练手,做为学习过程中的记录和 ...
- 使用Docker快速搭建Halo个人博客到阿里云服务器上[附加主题和使用域名访问]
一.前言 小编买了一个服务器也是一直想整个网站,一直在摸索,看了能够快速搭建博客系统的教程.总结了有以下几种方式,大家按照自己喜欢的去搭建: halo wordpress hexo vuepress ...
- 一文教您如何通过 Docker 快速搭建各种测试环境(Mysql, Redis, Elasticsearch, MongoDB) | 建议收藏
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 高级架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...
- 快速搭建应用服务日志收集系统(Filebeat + ElasticSearch + kibana)
快速搭建应用服务日志收集系统(Filebeat + ElasticSearch + kibana) 概要说明 需求场景,系统环境是CentOS,多个应用部署在多台服务器上,平时查看应用日志及排查问题十 ...
- Gerrit代码审计系统实战-Gerrit 2.15.14版本快速搭建
Gerrit代码审计系统实战-Gerrit 2.15.14版本快速搭建 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Gerrit版本选择 1>.查看Gerrit官网 ...
随机推荐
- authpuppy 认证服务器搭建
此文仅限于搭建authpuppy认证服务器,不包含认证插件等安装,仅说明步骤以备下次安装忘记步骤.耽误时间. 环境:ubuntu10.04 软件版本:authpuppy-1.0.0-stable.tg ...
- JAVA设计模式之 訪问者模式【Visitor Pattern】
一.概述 訪问者模式是一种较为复杂的行为型设计模式,它包括訪问者和被訪问元素两个主要组成部分.这些被訪问的元素通常具有不同的类型,且不同的訪问者能够对它们进行不同的訪问操作.在使用訪问者模式时,被訪问 ...
- 总结一些Android好用的开源库
1.android-viewFlow https://github.com/pakerfeldt/android-viewflow 2. android-viewbadger https://gith ...
- Spring中bean的生命周期!
Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...
- iOS GZWaterfall任何形式的瀑布流
概述 使用UICollectionView可以布局各种各样的瀑布流,下面我写了几种不同布局的瀑布流样式 详细 代码下载:http://www.demodashi.com/demo/11018.html ...
- 基于UML的面向对象分析与设计
前言 经常听到有朋友抱怨,说学了UML不知该怎么用,或者画了UML却觉得没什么作用.其实,就UML本身来说,它只是一种交流工具,它作为一种标准化交流符号,在OOA&D过程 ...
- 一招破解混淆后的JavaScript代码
http://www.cnblogs.com/zjyuan/archive/2011/12/14/2287647.html JavaScript不是很给力,想怎么破解就怎么破解!此文章教你的不仅仅是破 ...
- Android 读取<meta-data>元素中的数据
众所周知, 每个组件都有<meta-data>元素, 用于接收一些外部数据(eg: appKey), 那其中的值应该怎么读取呢. 1> Application <applica ...
- IHttpHandler的那些事
写在前面 从上家公司离职,在家休息,闲着无聊,觉得还是有必要将IHttpHanlder的内容,做一个总结.发现在写demo的过程中,总觉得有点生疏了,项目中很少使用自定义的类来实现该接口.当然,一般处 ...
- 公有/私有/保护继承、overload/overwrite/override之间的区别
一.继承 C++很重要的一个特征就是代码重用.在C语言中重用代码的方式就是拷贝代码.修改代码.C++可以用继承或组合的方式来重用.通过组合或继承现有的的类来创建新类,而不是重新创建它们. 继承是使用已 ...