Storage and manipulation of spatial data in MongoDB

Source: Internet
Author: User

This article uses the official C # Driver to implement storage in MongoDB, querying spatial data (vectors)


storage of spatial dataIn this example, the vector feature space information and the attribute table are read from a vector file (shapefile format) and written to MongoDB, where the ability to read Shapefile files and convert spatial information to JSON is implemented through the OGR library
 Open MongoDB's collection Mongodatabase db = Server.            Getdatabase ("AA"); Mongocollection Colsheng = db.            GetCollection ("Sheng");            Use the OGR library to open a Shapefile file DataSource ds = Ogr.open (@ "c:\temp\sheng.shp", 0); Layer Lyr = ds.            Getlayerbyindex (0); Reads the number of features and the number of fields int feacount = Lyr.            Getfeaturecount (0); int fieldcount = Lyr. Getlayerdefn ().            GetFieldCount ();            Read all field names list<string> FieldNames =new list<string> (); for (int i = 0; i < FieldCount; i++) {Fieldnames.add (LYR). Getlayerdefn (). Getfielddefn (i).            GetName ()); }//loop adds all features to MongoDB for (int i = 0; i < Feacount; i++) {//Use OGR library to convert vector The spatial information of the feature is turned into JSON format Feature FEA = Lyr.                Getfeature (i); Geometry Geo = fea.                      Getgeometryref (); String json = Geo.                                Exporttojson (NULL); BsondOcument doc = new bsondocument ();                  The spatial information in JSON format is stored in collection//bsonvalue bs = Bsonvalue.create (JSON);               This method is not possible, after adding to the library cannot use the Spatial query statement query Bsonvalue BS2 = Bsondocument.parse (JSON); This method is the correct//doc.                ADD (New Bsonelement ("Geom", BS)); Doc.                ADD (New Bsonelement ("Geo", BS2)); Collection The property information of all fields into a loop by looping for (int j = 0; J < FieldCount; J + +) {s Tring Tmpfieldval = fea.                    Getfieldasstring (j); Doc.                ADD (New Bsonelement (Fieldnames[j],tmpfieldval));                            } var res = colsheng.insert<bsondocument> (DOC); }



You can then look at what vector data is stored in MongoDB and enter it on the command line:
> Db.sheng.find (). Limit (1)


Result is
{"_id": ObjectId ("5371bf4e1dbba31914224563"), "Geo": {"type": "Polygon", "coordinates": [[[[89.8496], 14.093], [9 0.3933, 14.004], [90.2708, 13.4708], [89.7284, 13.5597], [89.8496, 14.093]]}, "Pyname": "SX", "Boxtype": "int Er "," date ":" 2012/6/5 12:41:42 "}


You can see this field named Geo, which is the coordinate information of vector features.
spatial Query and spatial indexThe available space operations include geointersect,geowithin,near, etc., reference http://docs.mongodb.org/manual/reference/operator/query-geospatial/ Here is an example of using Geointersect to illustrate:           
Get collection Mongodatabase db = Server.            Getdatabase ("AA"); Mongocollection Colsheng = db.                     GetCollection ("Sheng"); Define a query box or query polygon var poly = geojson.polygon<geojson2dcoordinates> (geojson.position (100, 20 ), Geojson.position (+), geojson.position (100, geojson.position),            , Max), Geojson.position (100, 20));            Define a query statement with this query polygon as a condition var queryFilter2 = query.geointersects ("Geo", poly); For query, output mongocursor cur = colsheng.findas<bsondocument> (queryFilter2).            Setfields ("Pyname", "date"); Get the result var res = cur.            ToArray (); for (int i = 0; i < Res. Count (); i++) {Bsondocument Tmpdoc = Res.                ElementAt (i); Do something Want}


For a spatial index, refer to http://docs.mongodb.org/manual/applications/geospatial-indexes/here, not in detail.
problems with Spatial query operations:When using Geointersect for spatial query, encountered the query results and ArcGIS inconsistent situation, a detailed look, like a MongoDB bug (currently using 2.6.0 version) the details are as follows (operate on the command line):
Coordinates in the collection
> 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]]}}



Query statements that are used
> Db.test.find ({"Geo": {"$geoIntersects": {"$geometry": {"type": "Polygon", "coordinates": [[[91.0], 33.0], [10 2.0, 33.0], [102.0, 38.0], [91.0, 38.0], [91.0, 33.0]]}}})



Query Result:
{"_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]]}}



But as you can see, there is only one record in collection, and the y-coordinate of all points in the record is greater than 38.0, why is this record in the query result intersect with the box in the statement ... It's weird.
Because of this problem, it is not reassuring to use the spatial query directly for the actual application, but through a flexible approach to the simple spatial query, the test found that it may be due to the problem of spatial index, this way query than the Geointersects method is faster
The general idea is: to generate a minimum bounding rectangle for each record, get its xmax,xmin,ymax,ymin four boundary value, save it in the form of numerical value to collection, each time the spatial query, first through the smallest external rectangle to filter, Judging the relationship between these minimum bounding rectangle and the smallest bounding rectangle of the polygon in the query statement, if intersecting, then the second step is judged by the OGR component to determine whether the actual polygon intersects, and the final result is the code that produces the smallest bounding rectangle:           
Get collection Mongodatabase db = Server.            Getdatabase ("AA"); Mongocollection colsheng= db.            GetCollection ("Sheng"); Query all records var cur = Colsheng.            Findallas<bsondocument> (); Long totalcount = cur.            Count (); Traverse all records for (int i = 0; I <= totalcount/1000; i++) {if (I * >= Totalcoun                T) 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 + +) {//Get a record corresponding to bsondocument bsondocument doc = lst[j];                    var id = doc["_id"]; The record corresponds to the id bsondocument geo = doc["Geo"].                            Tobsondocument (); String geostr = Geo[1].        ToString (); This record corresponds to the spatial information of the JSON string List<double> coords = getcoordlstfromstring (GEOSTR);        Parse the JSON string to get the coordinates of all points (where the sub-function is omitted) Double xmin = 181, Xmax = -181, ymin = Ymax = 91; Four boundary values, because the layer is latitude and longitude, the initial value is set to these values//calculates the maximum minimum value 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) Ymi                                n = coords[k];                            if (Coords[k] > Ymax) ymax = Coords[k]; }}//writes the maximum minimum value to 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); }                }



Then the code for the query:           
Get collection Mongodatabase db = Server.            Getdatabase ("AA"); Mongocollection Colsheng = db.            GetCollection ("zy02c"); The first step, through the four boundary filter, var query = Query.and (query.gt ("Xmax", 91.0), query.lt ("Xmin", 102.0), query.gt ("Ymax", 33.0), Q            uery.lt ("Ymin", 38.0));            var cur = colsheng.findas<bsondocument> (query);            Conditional polygons defining the second space operation (definition of the OGR format) 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); The result of the circular query is var lst = cur.            ToArray (); for (int i = LST. Length-1; I >=0;             i--) {//Get bsondocument for the current record   Bsondocument doc = Lst[i];            var id = doc["_id"]; The ID of the current record bsondocument geo = doc["Geo"].                Tobsondocument (); String geostr = Geo[1].        ToString (); The JSON string that corresponds to the spatial information of the current record//Gets the coordinate value through the JSON string and generates the corresponding Geometry object list<double> coor                ds = 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); Determines whether the geometry and conditional polygons intersect if (resgeo.intersects (Querygeo)) {//do some Thing}}


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.