MongoDB中空间数据的存储和操作
本文使用官方C# Driver,实现在MongoDB中存储,查询空间数据(矢量)
- //打开MongoDB的Collection
- MongoDatabase db = server.GetDatabase("aa");
- MongoCollection colSheng = db.GetCollection("sheng");
- //使用Ogr库打开Shapefile文件
- DataSource ds = Ogr.Open(@"c:\temp\sheng.shp", 0);
- Layer lyr = ds.GetLayerByIndex(0);
- //读取要素数量和字段数量
- int feaCount = lyr.GetFeatureCount(0);
- int fieldCount = lyr.GetLayerDefn().GetFieldCount();
- //读取所有字段名
- List<string> fieldNames =new List<string>();
- for (int i = 0; i < fieldCount; i++)
- {
- fieldNames.Add(lyr.GetLayerDefn().GetFieldDefn(i).GetName());
- }
- //循环将所有要素添加到MongoDB中
- for (int i = 0; i < feaCount; i++)
- {
- //使用Ogr库将矢量要素的空间信息转成Json格式
- Feature fea = lyr.GetFeature(i);
- Geometry geo = fea.GetGeometryRef();
- string json = geo.ExportToJson(null);
- BsonDocument doc = new BsonDocument();
- //将Json格式的空间信息存到Collection中
- //BsonValue bs = BsonValue.Create(json); //这种方法是不可以的,添加到库里之后无法使用空间查询语句查询
- BsonValue bs2 = BsonDocument.Parse(json); //这种方法才是正确的
- //doc.Add(new BsonElement("geom", bs));
- doc.Add(new BsonElement("geo",bs2));
- //通过循环将所有字段的属性信息存入Collection中
- for (int j = 0; j < fieldCount; j++)
- {
- string tmpFieldVal = fea.GetFieldAsString(j);
- doc.Add(new BsonElement(fieldNames[j],tmpFieldVal));
- }
- var res = colSheng.Insert<BsonDocument>(doc);
- }
- > db.sheng.find().limit(1)
- { "_id" : ObjectId("5371bf4e1dbba31914224563"), "geo" : { "type" : "Polygon", "coordinates" : [ [ [ 89.8496, 14.093 ], [ 90.3933, 14.004 ], [ 90.2708, 13.4708 ], [ 89.7284, 13.5597 ], [ 89.8496, 14.093 ] ] ] }, "pyname" : "sx", "boxtype" : "inter", "date" : "2012/6/5 12:41:42" }
- //获取Collection
- MongoDatabase db = server.GetDatabase("aa");
- MongoCollection colSheng = db.GetCollection("sheng");
- //定义一个查询框或查询多边形
- var poly = GeoJson.Polygon<GeoJson2DCoordinates>(
- GeoJson.Position(100, 20),
- GeoJson.Position(110, 20),
- GeoJson.Position(110, 40),
- GeoJson.Position(100, 40),
- GeoJson.Position(100, 20));
- //以这个查询多边形为条件定义一条查询语句
- var queryFilter2 = Query.GeoIntersects("geo", poly);
- //进行查询,输出MongoCursor
- cur = colSheng.FindAs<BsonDocument>(queryFilter2).SetFields( "pyname", "date");
- //获取结果
- var res = cur.ToArray();
- for (int i = 0; i < res.Count(); i++)
- {
- BsonDocument tmpDoc = res.ElementAt(i);
- //do something you want
- }
- > db.test.find()
- { "_id" : ObjectId("535884771dbba31858ad2101"), "geo" : { "type" : "Polygon", "coordinates" : [ [ [ 96.722, 38.755 ], [ 97.3482, 38.6922 ], [ 97.1674, 38.0752 ], [ 96.5474, 38.1383 ], [ 96.722, 38.755 ] ] ] } }
使用的查询语句
- > db.test.find({ "geo" : { "$geoIntersects" : { "$geometry" : { "type" : "Polygon", "coordinates" : [[[91.0, 33.0], [102.0, 33.0], [102.0, 38.0], [91.0, 38.0], [91.0, 33.0]]] } } } })
查询结果:
- { "_id" : ObjectId("535884771dbba31858ad2101"), "geo" : { "type" : "Polygon", "coordinates" : [ [ [ 96.722, 38.755 ], [ 97.3482, 38.6922 ], [ 97.1674, 38.0752 ], [ 96.5474, 38.1383 ], [ 96.722, 38.755 ] ] ] } }
但可以看到,collection中只有一条记录,且该记录所有点的Y坐标均大于38.0,为什么查询结果里,这条记录与语句中的Box相交呢。。。很奇怪
因为有这样的问题,所以还不放心直接将空间查询用于实际应用,而是通过一种变通的方法进行简单的空间查询,测试后发现,可能是由于空间索引的问题,这种方式查询比自带的GeoIntersects方法要快
- //获取Collection
- MongoDatabase db = server.GetDatabase("aa");
- MongoCollection colsheng= db.GetCollection("sheng");
- //查询所有记录
- var cur = colsheng.FindAllAs<BsonDocument>();
- long totalCount = cur.Count();
- //遍历所有记录
- for (int i = 0; i <= totalCount/1000; i++)
- {
- if (i * 1000 >= totalCount) continue;
- int skip = i * 1000;
- var cur2 = cur.Clone<BsonDocument>().SetSkip(skip).SetLimit(1000);
- var lst = cur2.ToArray();
- for (int j = 0; j < lst.Count(); j++)
- {
- //获取一条记录对应的BsonDocument
- BsonDocument doc = lst[j];
- var id = doc["_id"]; //该记录对应的ID
- BsonDocument geo = doc["geo"].ToBsonDocument();
- string geostr = geo[1].ToString(); //该记录对应空间信息的Json字符串
- List<double> coords = GetCoordLstFromString(geostr); //解析Json串,获得所有点的坐标(这里子函数就省略了)
- double xmin = 181, xmax = -181, ymin = 91, ymax = -91; //四个边界值,由于图层为经纬度,所以初值设为这些值
- //计算最大最小值
- for (int k = 0; k < coords.Count; k++)
- {
- if (k % 2 == 0)
- {
- if (coords[k] < xmin) xmin = coords[k];
- if (coords[k] > xmax) xmax = coords[k];
- }
- else
- {
- if (coords[k] < ymin) ymin = coords[k];
- if (coords[k] > ymax) ymax = coords[k];
- }
- }
- //将最大最小值写入Collection
- var tmpQuery = Query.EQ("_id", id);
- var tmpUpdate = MongoDB.Driver.Builders.Update.Set("xmax", xmax);
- var tmpres = col02c.Update(tmpQuery, tmpUpdate);
- tmpUpdate = MongoDB.Driver.Builders.Update.Set("xmin", xmin);
- tmpres = col02c.Update(tmpQuery, tmpUpdate);
- tmpUpdate = MongoDB.Driver.Builders.Update.Set("ymax", ymax);
- tmpres = col02c.Update(tmpQuery, tmpUpdate);
- tmpUpdate = MongoDB.Driver.Builders.Update.Set("ymin", ymin);
- tmpres = col02c.Update(tmpQuery, tmpUpdate);
- }
- }
- //获取Collection
- MongoDatabase db = server.GetDatabase("aa");
- MongoCollection colSheng = db.GetCollection("zy02c");
- //第一步,通过四边界筛选,
- var query = Query.And(Query.GT("xmax", 91.0), Query.LT("xmin", 102.0), Query.GT("ymax", 33.0), Query.LT("ymin", 38.0));
- var cur = colSheng.FindAs<BsonDocument>(query);
- //定义第二空间运算时的条件多边形(Ogr格式的定义)
- Geometry queryGeoLR = new Geometry(wkbGeometryType.wkbLinearRing);
- queryGeoLR.AddPoint(91.0, 33.0,0);
- queryGeoLR.AddPoint(102.0, 33.0,0);
- queryGeoLR.AddPoint(102.0, 38.0,0);
- queryGeoLR.AddPoint(91.0, 38.0,0);
- queryGeoLR.AddPoint(91.0, 33.0,0);
- Geometry queryGeo = new Geometry(wkbGeometryType.wkbPolygon);
- queryGeo.AddGeometry(queryGeoLR);
- //循环查询到的结果
- var lst = cur.ToArray();
- for (int i = lst.Length-1; i >=0; i--)
- {
- //获取当前记录对应的BsonDocument
- BsonDocument doc = lst[i];
- var id = doc["_id"]; //当前记录的ID
- BsonDocument geo = doc["geo"].ToBsonDocument();
- string geostr = geo[1].ToString(); //当前记录对应空间信息的Json字符串
- //通过Json串获取坐标值,并生成对应的Geometry对象
- List<double> coords = GetCoordLstFromString(geostr);
- Geometry resGeoLR = new Geometry(wkbGeometryType.wkbLinearRing);
- for (int j = 0; j < coords.Count / 2; j++)
- {
- resGeoLR.AddPoint_2D(coords[j], coords[j + 1]);
- }
- resGeoLR.AddPoint_2D(coords[0], coords[1]);
- Geometry resGeo = new Geometry(wkbGeometryType.wkbPolygon);
- resGeo.AddGeometry(resGeoLR);
- //判断是该Geometry与条件多边形是否相交
- if (resGeo.Intersects(queryGeo))
- {
- //do something
- }
- }
MongoDB中空间数据的存储和操作的更多相关文章
- MongoDB中数组类型相关的操作
概述 在MongoDB的模式中,我们经常将一些数据存储到数组类型中,即我们常见的嵌套模式设计的一种实现方式.数组的这种设计实现方式在关系数据库中是没有或者说不常见的.所以,通过本文我们来梳理一下Mon ...
- 利用“海底捞算法”在MongoDB中优雅地存储一棵树
目前常见的树形结构数据库存储方案有以下四种,但是在处理无限深度.海量数据的树结构时,都存在一些问题: 1)Adjacency List(邻接表):每个节点仅记录父节点主键.优点是简单,缺点是访问子树需 ...
- MongoDB地理空间数据存储及检索
目录 1.存入地理数据 GeoJSON数据存入 1.Ponit 点数据 2.LineString 线数据(多段线) 3. Polygon 多边形数据 4.MultiPoint多点.MultiLineS ...
- 在MongoDB中使用JOIN操作
SQL与NoSQL最大的不同之一就是不支持JOIN,在传统的数据库中,SQL JOIN子句允许你使用普通的字段,在两个或者是更多表中的组合表中的每行数据.例如,如果你有表books和publisher ...
- php操作mongodb中的ISODate格式日期
mongodb 中数据记录的日期格式为"dateCreated" : ISODate("2011-12-20T07:22:50.836Z")经过翻阅php官网中 ...
- 【转载】MongoDB中的MapReduce 高级操作介绍
转载自残缺的孤独 1.概述 MongoDB中的MapReduce相当于关系数据库中的group by.使用MapReduce要实现两个函数Map和Reduce函数.Map函数调用emit(key,va ...
- MongoDB中的映射,限制记录和记录拼排序 文档的插入查询更新删除操作
映射 在 MongoDB 中,映射(Projection)指的是只选择文档中的必要数据,而非全部数据.如果文档有 5 个字段,而你只需要显示 3 个,则只需选择 3 个字段即可. find() 方法 ...
- Java POJO类直接存储在MongoDB中
记录Java POJO类直接存储在MongoDB中的策略. maven: <dependency> <groupId>org.mongodb</groupId> & ...
- 爬取豆瓣电影TOP 250的电影存储到mongodb中
爬取豆瓣电影TOP 250的电影存储到mongodb中 1.创建项目sp1 PS D:\scrapy> scrapy.exe startproject douban 2.创建一个爬虫 PS D: ...
随机推荐
- 实验1 单片机IO口应用及数码管显示
1. 单片机驱动蜂鸣器的实验: a) 说明:Lab51单片机实验板的蜂鸣器连接到单片机的P1.5 b) 基本要求:控制蜂鸣器每2秒响0.5秒. #include &l ...
- MySql字段类型说明
bigint 从 -^ (-) 到 ^- () 的整型数据(所有数字).存储大小为 个字节. P.S. bigint已经有长度了,在mysql建表中的length,只是用于显示的位数 int 从 -^ ...
- java实现点选汉字验证码
package com.rd.p2p.web; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; im ...
- lua编程之lua与C相互调用
lua是扩展性非常良好的语言,虽然核心非常精简,但是用户可以依靠lua库来实现大部分工作.除此之外,lua还可以通过与C函数相互调用来扩展程序功能.在C中嵌入lua脚本既可以让用户在不重新编译代码的情 ...
- 05_python_字典
一.字典定义 字典是python中唯一的映射类型,以{ }括起来的键值对组成,在dict中key是唯一的.在保存时,根据key来计算一个内存地址,然后把key-value保存至地址中.这种算法是has ...
- 反向读取Mysql数据库表结构到PowerDesigner中
使用PowerDesigner挺长时间了,只是一些简单的表结构设计,因需要对当前数据库进行再设计,需要看一下数据库中所有的表,及表之间的关系,并重新修改表结构,因此需求就是怎么把数据库中的表结构反向生 ...
- python学习笔记10-文件操作
能调用方法的一定是对象.文件本身也是一个对象.有很多自己内置的方法 #操作文件第一件事 建立文件对象 open函数 # 参数一:文件路径 绝对路径和相对路径都可以 # 参数二:模式选择 ‘r’ 读模式 ...
- 关于c++类的一些知识的总结
1.经常会听到“类的声明.类的定义.类的实现”,它们之间有什么不一样? 经过查阅https://www.cnblogs.com/kkshaq/p/4660073.html博客的说法,类的声明是在.h文 ...
- WIN10安装scrapy/channels等不成功的解决方式
问题 在Win10机器上,不管是安装scrapy还是channels,都需要安装一个包,叫做twisted.正是这个twisted,导致出现一系列的奇葩错误,让我一度以为我的Pycharm坏了,还改了 ...
- Scala使用Akka模拟RPC机制代码
上代码: 另一个版本(自己加注释):http://www.cnblogs.com/DreamDrive/p/6740440.html RemoteMessage.scala trait Remote ...