This article uses the official C # Driver to store and query spatial data (vectors) in MongoDB)
Storage of Spatial DataIn this example, the vector element space information and Attribute Table are read from a Vector file (shapefile format) and written to MongoDB, the function of reading the shapefile and converting the space information into json is implemented through the Ogr library.
// Open the Collection objects database db = server of MongoDB. getDatabase ("aa"); repeated collection colSheng = db. getCollection ("sheng"); // use the Ogr library to open the Shapefile file DataSource ds = Ogr. open (@ "c: \ temp \ sheng. shp ", 0); Layer lyr = ds. getLayerByIndex (0); // Number of read elements and field count int feaCount = lyr. getFeatureCount (0); int fieldCount = lyr. getLayerDefn (). getFieldCount (); // read the List of all field names <string> fieldNames = new List <string> (); for (int I = 0; I <fieldCount; I ++) {fieldNames. add (lyr. getLayerDefn (). getFieldDefn (I ). getName () ;}// cyclically add all elements to MongoDB for (int I = 0; I <feaCount; I ++) {// use the Ogr library to convert the space information of vector elements to the Json format Feature fea = lyr. getFeature (I); Geometry geo = fea. getGeometryRef (); string json = geo. exportToJson (null); BsonDocument doc = new BsonDocument (); // Save the space information in Json format to the Collection. // BsonValue bs = BsonValue. create (json); // This method is not allowed. After being added to the library, you cannot use the space query statement to query BsonValue bs2 = BsonDocument. parse (json); // This method is correct // doc. add (new BsonElement ("geom", bs); doc. add (new BsonElement ("geo", bs2); // store the attribute information of all fields in the Collection using a loop 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 );}
Then, you can view the vector data stored in MongoDB and input it in the command line:
> db.sheng.find().limit(1)
Result:
{ "_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" }
The Field named geo is displayed, and the coordinates of the vector elements are stored in the Field.
Spatial Query and spatial indexAvailable space operations include geointersect, geowithin, and near:
// Obtain Collection objects database db = server. getDatabase ("aa"); repeated collection colSheng = db. getCollection ("sheng"); // define a query box or query a polygon 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); // defines a Query statement var queryFilter2 = Query based on the Query polygon. geoIntersects ("geo", poly); // query, and export cursor cur = colSheng. findAs <BsonDocument> (queryFilter2 ). setFields ("pyname", "date"); // obtain the result var res = cur. toArray (); for (int I = 0; I <res. count (); I ++) {BsonDocument tmpDoc = res. elementAt (I); // do something you want}
For details about spatial indexes, refer to http://docs.mongodb.org/manual/applications/geospatial-indexes /.
Space query operation problems:When GeoIntersect is used for spatial queries, the query results are inconsistent with ArcGIS. For details, see a BUG in MongoDB (2.6.0 is used currently) the specific information is as follows (in the command line ):
Coordinates in 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 statement used
> 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]]] } } } })
Query results:
{ "_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 we can see that there is only one record in the collection, and the Y coordinate of all points of the record is greater than 38.0. Why does this record intersect with the Box in the statement in the query result... Very strange
Because of this problem, it is not easy to directly use the space query for practical applications. Instead, it uses a flexible method to perform simple space query. After testing, it is found that, this may be due to spatial index problems. This method is faster than the built-in GeoIntersects method.
The general idea is: generate a minimum external rectangle for each record, and obtain the xmax, xmin, ymax, and ymin boundary values, which are saved to the Collection as numerical values, when performing a spatial query, filter the smallest external rectangle first to determine the relationship between the smallest external rectangle and the smallest external rectangle of the polygon in the query statement, the second step is to judge whether the actual polygon is intersecting by using the Ogr component. The final result returned is the code that generates the smallest external rectangle first:
// Obtain Collection objects database db = server. getDatabase ("aa"); repeated collection 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 * 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 ++) {// obtain the BsonDocument doc = lst [j] for a record; var id = doc ["_ id"]; // The ID BsonDocument geo = doc ["geo"] corresponding to the record. toBsonDocument (); string geostr = geo [1]. toString (); // List of Json strings corresponding to the spatial information of the record <double> coords = GetCoordLstFromString (geostr); // parse the Json string, obtain the coordinates of all points (here the subfunction is omitted) double xmin = 181, xmax =-181, ymin = 91, ymax =-91; // Four boundary values, since the layer is longitude and latitude, the initial values are set to these values // calculate the maximum and minimum values 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] ;}// write the maximum and minimum values to the 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 there is the query code:
// Obtain Collection objects database db = server. getDatabase ("aa"); repeated collection colSheng = db. getCollection ("zy02c"); // Step 1: Filter by four boundaries. 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); // defines the condition polygon (defined in the Ogr format) during the second Space Operation 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 returned by the loop query var lst = cur. toArray (); for (int I = lst. length-1; I> = 0; I --) {// obtain 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 of the space information of the current record // obtain the coordinate value through the Json string and generate the corresponding Geometry Object 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); // determines whether the Geometry and the condition polygon are intersecting if (resGeo. intersects (queryGeo) {// do something }}