1 /******************************************************************************
2 *
3 * Project: MongoDB Translator
4 * Purpose: Implements OGRMongoDBDriver.
5 * Author: Even Rouault, even.rouault at spatialys.com
6 *
7 ******************************************************************************
8 * Copyright (c) 2014-2019, Even Rouault <even dot rouault at spatialys dot com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "mongocxxv3_headers.h"
31
32 #include "cpl_time.h"
33 #include "gdal_priv.h"
34 #include "ogrsf_frmts.h"
35 #include "ogr_p.h"
36
37 #include <limits>
38 #include <map>
39 #include <memory>
40 #include <mutex>
41 #include <vector>
42
43 extern "C" void CPL_DLL RegisterOGRMongoDBv3();
44
45 // g++ -Wall -Wextra -std=c++11 -fPIC -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -I$HOME/install-mongocxx-3.4.0/include/bsoncxx/v_noabi -I$HOME/install-mongocxx-3.4.0/include/mongocxx/v_noabi ogr/ogrsf_frmts/mongodbv3/ogrmongodbv3driver.cpp -shared -o ogr_MongoDBv3.so -L$HOME/install-mongocxx-3.4.0/lib -lmongocxx -lgdal
46
47 using bsoncxx::builder::basic::kvp;
48
49 static mongocxx::instance* g_pInst = nullptr;
50 static bool g_bCanInstantiateMongo = true;
51
52 namespace {
53 typedef struct _IntOrMap IntOrMap;
54
55 struct _IntOrMap
56 {
57 int bIsMap;
58 union
59 {
60 int nField;
61 std::map< CPLString, IntOrMap*>* poMap;
62 } u;
63 };
64 } // namespace
65
66 class OGRMongoDBv3Layer;
67
68 class OGRMongoDBv3Dataset final: public GDALDataset
69 {
70 friend class OGRMongoDBv3Layer;
71
72 mongocxx::client m_oConn{};
73 CPLString m_osDatabase{};
74 std::vector<std::unique_ptr<OGRMongoDBv3Layer>> m_apoLayers{};
75 bool m_bFlattenNestedAttributes = false;
76 int m_nBatchSize = 0;
77 int m_nFeatureCountToEstablishFeatureDefn = 0;
78 bool m_bJSonField = false;
79 CPLString m_osFID{};
80 bool m_bUseOGRMetadata = true;
81 bool m_bBulkInsert = true;
82
83 void CreateLayers(mongocxx::database& db);
84
85 public:
86 OGRMongoDBv3Dataset() = default;
87
GetLayerCount()88 int GetLayerCount() override { return static_cast<int>(m_apoLayers.size()); }
89 OGRLayer* GetLayer(int) override;
90 OGRLayer* GetLayerByName(const char* pszLayerName) override;
91
92 OGRLayer * ExecuteSQL( const char *pszSQLCommand,
93 OGRGeometry *poSpatialFilter,
94 const char *pszDialect ) override;
95 void ReleaseResultSet( OGRLayer * poLayer ) override;
96
97 OGRLayer* ICreateLayer( const char *pszName,
98 OGRSpatialReference *poSpatialRef,
99 OGRwkbGeometryType eGType,
100 char ** papszOptions ) override;
101 OGRErr DeleteLayer( int iLayer ) override;
102 int TestCapability( const char * pszCap ) override;
103
104
105 bool Open(GDALOpenInfo* poOpenInfo);
106 };
107
108 class OGRMongoDBv3Layer final: public OGRLayer
109 {
110 friend class OGRMongoDBv3Dataset;
111
112 OGRMongoDBv3Dataset* m_poDS = nullptr;
113 OGRFeatureDefn* m_poFeatureDefn = nullptr;
114 bool m_bHasEstablishedFeatureDefn = false;
115 mongocxx::database m_oDb{};
116 mongocxx::collection m_oColl{};
117 CPLString m_osFID{};
118 bsoncxx::document::value m_oQueryAttr{bsoncxx::builder::basic::make_document()};
119 bsoncxx::document::value m_oQuerySpat{bsoncxx::builder::basic::make_document()};
120 bool m_bLayerMetadataUpdatable = false;
121 bool m_bUpdateLayerMetadata = false;
122 bool m_bDotAsNestedField = true;
123 bool m_bIgnoreSourceID = false;
124 bool m_bCreateSpatialIndex = true;
125 GIntBig m_nIndex = 0;
126 GIntBig m_nNextFID = 0;
127 std::unique_ptr<mongocxx::cursor> m_poCursor{};
128 std::unique_ptr<mongocxx::cursor::iterator> m_poIterator{};
129
130 std::vector< std::vector<CPLString> > m_aaosFieldPaths{};
131
132 std::vector< std::vector<CPLString> > m_aaosGeomFieldPaths{};
133 std::vector< CPLString > m_aosGeomIndexes{};
134 std::vector< std::unique_ptr<OGRCoordinateTransformation> > m_apoCT{};
135
136 std::map< CPLString, CPLString> CollectGeomIndices();
137 bool ReadOGRMetadata(std::map< CPLString, CPLString>& oMapIndices);
138 void EstablishFeatureDefn();
139 void WriteOGRMetadata();
140 void AddOrUpdateField(const char* pszAttrName,
141 const bsoncxx::document::element& elt,
142 char chNestedAttributeSeparator,
143 std::vector<CPLString>& aosPaths,
144 std::map< CPLString, CPLString>& oMapIndices);
145 std::unique_ptr<OGRFeature> Translate(const bsoncxx::document::view& doc);
146 bsoncxx::document::value BuildQuery();
147
148 void SerializeField(bsoncxx::builder::basic::document& b,
149 OGRFeature *poFeature,
150 int iField,
151 const char* pszJSonField);
152 void SerializeGeometry(bsoncxx::builder::basic::document& b,
153 OGRGeometry* poGeom, int iField,
154 const char* pszJSonField);
155 void SerializeRecursive(bsoncxx::builder::basic::document& b,
156 OGRFeature *poFeature,
157 std::map< CPLString, IntOrMap*>& aoMap );
158 static void InsertInMap(IntOrMap* rootMap,
159 std::map< std::vector<CPLString>, IntOrMap*>& aoMap,
160 const std::vector<CPLString>& aosFieldPathFull,
161 int nField);
162 bsoncxx::document::value BuildBSONObjFromFeature(OGRFeature* poFeature, bool bUpdate);
163 std::vector<bsoncxx::document::value> m_aoDocsToInsert{};
164
165 public:
166 OGRMongoDBv3Layer(OGRMongoDBv3Dataset* poDS,
167 const std::string& osDbName,
168 const std::string& osCollection);
169 ~OGRMongoDBv3Layer() override;
170
171 void ResetReading() override;
172 const char* GetFIDColumn() override;
173 OGRFeature* GetNextFeature() override;
174 OGRFeature* GetFeature(GIntBig nFID) override;
175 OGRErr DeleteFeature(GIntBig nFID) override;
176 GIntBig GetFeatureCount(int bForce) override;
177 OGRErr SetAttributeFilter(const char* pszFilter) override;
SetSpatialFilter(OGRGeometry * poGeom)178 void SetSpatialFilter( OGRGeometry *poGeom ) override { SetSpatialFilter(0, poGeom); }
179 void SetSpatialFilter( int iGeomField, OGRGeometry *poGeom ) override;
180 int TestCapability( const char* pszCap ) override;
181 OGRFeatureDefn* GetLayerDefn() override;
182 OGRErr CreateField( OGRFieldDefn *poFieldIn, int ) override;
183 OGRErr CreateGeomField( OGRGeomFieldDefn *poFieldIn, int ) override;
184 OGRErr ICreateFeature( OGRFeature *poFeature ) override;
185 OGRErr ISetFeature( OGRFeature *poFeature ) override;
186
187 OGRErr SyncToDisk() override;
188
189 };
190
191 /************************************************************************/
192 /* OGRMongoDBv3Layer() */
193 /************************************************************************/
194
OGRMongoDBv3Layer(OGRMongoDBv3Dataset * poDS,const std::string & osDbName,const std::string & osCollection)195 OGRMongoDBv3Layer::OGRMongoDBv3Layer(OGRMongoDBv3Dataset* poDS,
196 const std::string& osDbName,
197 const std::string& osCollection) :
198 m_poDS(poDS)
199 {
200 CPLString osLayerName;
201 m_oDb = m_poDS->m_oConn[osDbName];
202 m_oColl = m_oDb[osCollection];
203 if( m_poDS->m_osDatabase == osDbName )
204 osLayerName = osCollection;
205 else
206 osLayerName = osDbName + "." + osCollection;
207 m_poFeatureDefn = new OGRFeatureDefn(osLayerName);
208 m_poFeatureDefn->Reference();
209 m_poFeatureDefn->SetGeomType(wkbNone);
210 SetDescription(m_poFeatureDefn->GetName());
211
212 OGRFieldDefn oFieldDefn("_id", OFTString);
213 std::vector<CPLString> aosPath;
214 aosPath.push_back("_id");
215 m_aaosFieldPaths.push_back(aosPath);
216 m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
217 }
218
219 /************************************************************************/
220 /* ~OGRMongoDBv3Layer() */
221 /************************************************************************/
222
~OGRMongoDBv3Layer()223 OGRMongoDBv3Layer::~OGRMongoDBv3Layer()
224 {
225 OGRMongoDBv3Layer::SyncToDisk();
226
227 if( m_poFeatureDefn )
228 m_poFeatureDefn->Release();
229 }
230
231 /************************************************************************/
232 /* WriteOGRMetadata() */
233 /************************************************************************/
234
WriteOGRMetadata()235 void OGRMongoDBv3Layer::WriteOGRMetadata()
236 {
237 //CPLDebug("MongoDBv3", "WriteOGRMetadata(%s)", m_poFeatureDefn->GetName());
238 if( !m_bUpdateLayerMetadata )
239 return;
240 m_bUpdateLayerMetadata = false;
241
242 try
243 {
244 bsoncxx::builder::basic::document b;
245
246 b.append(kvp("layer", m_oColl.name()));
247
248 if( !m_osFID.empty() )
249 {
250 b.append(kvp("fid", m_osFID));
251 }
252
253 bsoncxx::builder::basic::array fields;
254
255 CPLAssert( static_cast<int>(m_aaosFieldPaths.size()) == m_poFeatureDefn->GetFieldCount() );
256 for(int i=1;i<m_poFeatureDefn->GetFieldCount();i++)
257 {
258 OGRFieldDefn* poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
259 const char* pszFieldName = poFieldDefn->GetNameRef();
260 if( EQUAL(pszFieldName, "_json") )
261 continue;
262 bsoncxx::builder::basic::array path;
263 for(int j=0;j<static_cast<int>(m_aaosFieldPaths[i].size());j++)
264 path.append(m_aaosFieldPaths[i][j]);
265 bsoncxx::builder::basic::document rec;
266 rec.append(kvp("name", pszFieldName));
267 OGRFieldType eType = poFieldDefn->GetType();
268 rec.append(kvp("type", OGR_GetFieldTypeName(eType)));
269 if( eType == OFTInteger && poFieldDefn->GetSubType() == OFSTBoolean )
270 {
271 rec.append(kvp("subtype", "Boolean"));
272 }
273 rec.append(kvp("path", path.extract()));
274 fields.append(rec.extract());
275 }
276 b.append(kvp("fields", fields.extract()));
277
278 bsoncxx::builder::basic::array geomfields;
279 CPLAssert( static_cast<int>(m_aaosGeomFieldPaths.size()) == m_poFeatureDefn->GetGeomFieldCount() );
280 for(int i=0;i<m_poFeatureDefn->GetGeomFieldCount();i++)
281 {
282 OGRGeomFieldDefn* poGeomFieldDefn = m_poFeatureDefn->GetGeomFieldDefn(i);
283 const char* pszFieldName = poGeomFieldDefn->GetNameRef();
284 bsoncxx::builder::basic::array path;
285 for(int j=0;j<static_cast<int>(m_aaosGeomFieldPaths[i].size());j++)
286 path.append(m_aaosGeomFieldPaths[i][j]);
287 const char* pszGeomType = OGRToOGCGeomType(poGeomFieldDefn->GetType());
288 bsoncxx::builder::basic::document rec;
289 rec.append(kvp("name", pszFieldName));
290 rec.append(kvp("type", pszGeomType));
291 rec.append(kvp("path", path.extract()));
292 geomfields.append(rec.extract());
293 }
294 b.append(kvp("geomfields", geomfields.extract()));
295
296 {
297 bsoncxx::builder::basic::document filter{};
298 filter.append(kvp("layer", m_oColl.name()));
299 m_oDb["_ogr_metadata"].find_one_and_delete(filter.extract());
300 }
301
302 m_oDb["_ogr_metadata"].insert_one( b.extract() );
303 }
304 catch( const std::exception &ex )
305 {
306 CPLError(CE_Failure, CPLE_AppDefined, "%s: %s",
307 "WriteOGRMetadata()", ex.what());
308 }
309 }
310
311 /************************************************************************/
312 /* SyncToDisk() */
313 /************************************************************************/
314
SyncToDisk()315 OGRErr OGRMongoDBv3Layer::SyncToDisk()
316 {
317 try
318 {
319 if( !m_aoDocsToInsert.empty() )
320 {
321 m_oColl.insert_many( m_aoDocsToInsert.begin(), m_aoDocsToInsert.end() );
322 m_aoDocsToInsert.clear();
323 }
324 }
325 catch( const std::exception &ex )
326 {
327 m_aoDocsToInsert.clear();
328 CPLError(CE_Failure, CPLE_AppDefined, "%s: %s",
329 "CreateFeature()", ex.what());
330 return OGRERR_FAILURE;
331 }
332
333 WriteOGRMetadata();
334
335 return OGRERR_NONE;
336 }
337
338 /************************************************************************/
339 /* ResetReading() */
340 /************************************************************************/
341
ResetReading()342 void OGRMongoDBv3Layer::ResetReading()
343 {
344 m_poCursor.reset();
345 m_poIterator.reset();
346 m_nIndex = 0;
347 }
348
349 /************************************************************************/
350 /* GetLayerDefn() */
351 /************************************************************************/
352
GetLayerDefn()353 OGRFeatureDefn* OGRMongoDBv3Layer::GetLayerDefn()
354 {
355 if( !m_bHasEstablishedFeatureDefn )
356 EstablishFeatureDefn();
357
358 return m_poFeatureDefn;
359 }
360
361 /************************************************************************/
362 /* OGRMongoDBv3GetFieldTypeFromBSON() */
363 /************************************************************************/
364
365 static
OGRMongoDBv3GetFieldTypeFromBSON(const bsoncxx::document::element & elt,OGRFieldSubType & eSubType)366 OGRFieldType OGRMongoDBv3GetFieldTypeFromBSON(
367 const bsoncxx::document::element& elt,
368 OGRFieldSubType& eSubType )
369 {
370 eSubType = OFSTNone;
371
372 auto eBSONType = elt.type();
373 if( eBSONType == bsoncxx::type::k_bool )
374 {
375 eSubType = OFSTBoolean;
376 return OFTInteger;
377 }
378 else if( eBSONType == bsoncxx::type::k_double )
379 return OFTReal;
380 else if( eBSONType == bsoncxx::type::k_int32 )
381 return OFTInteger;
382 else if( eBSONType == bsoncxx::type::k_int64 )
383 return OFTInteger64;
384 else if( eBSONType == bsoncxx::type::k_utf8 )
385 return OFTString;
386 else if( eBSONType == bsoncxx::type::k_array )
387 {
388 auto arrayView = elt.get_array().value;
389 if( arrayView.empty() )
390 return OFTStringList; /* we don't know, so let's assume it is a string list */
391 OGRFieldType eType = OFTIntegerList;
392 bool bOnlyBoolean = true;
393 for (auto&& subElt : arrayView)
394 {
395 eBSONType = subElt.type();
396
397 bOnlyBoolean &= (eBSONType == bsoncxx::type::k_bool);
398 if (eBSONType == bsoncxx::type::k_double)
399 eType = OFTRealList;
400 else if (eType == OFTIntegerList && eBSONType == bsoncxx::type::k_int64)
401 eType = OFTInteger64List;
402 else if (eBSONType != bsoncxx::type::k_int32 &&
403 eBSONType != bsoncxx::type::k_int64 &&
404 eBSONType != bsoncxx::type::k_bool)
405 return OFTStringList;
406 }
407 if( bOnlyBoolean )
408 eSubType = OFSTBoolean;
409 return eType;
410 }
411 else if( eBSONType == bsoncxx::type::k_date )
412 return OFTDateTime;
413 else if( eBSONType == bsoncxx::type::k_binary )
414 return OFTBinary;
415 else
416 return OFTString; /* null, object */
417 }
418
419 /************************************************************************/
420 /* AddOrUpdateField() */
421 /************************************************************************/
422
AddOrUpdateField(const char * pszAttrName,const bsoncxx::document::element & elt,char chNestedAttributeSeparator,std::vector<CPLString> & aosPaths,std::map<CPLString,CPLString> & oMapIndices)423 void OGRMongoDBv3Layer::AddOrUpdateField(const char* pszAttrName,
424 const bsoncxx::document::element& elt,
425 char chNestedAttributeSeparator,
426 std::vector<CPLString>& aosPaths,
427 std::map< CPLString, CPLString>& oMapIndices)
428 {
429 const auto eBSONType = elt.type();
430 if( eBSONType == bsoncxx::type::k_null ||
431 eBSONType == bsoncxx::type::k_undefined ||
432 eBSONType == bsoncxx::type::k_minkey ||
433 eBSONType == bsoncxx::type::k_maxkey )
434 return;
435
436 if( eBSONType == bsoncxx::type::k_document )
437 {
438 bsoncxx::document::view doc{elt.get_document()};
439 auto eltType = doc["type"];
440 if( eltType && eltType.type() == bsoncxx::type::k_utf8 )
441 {
442 OGRwkbGeometryType eGeomType = OGRFromOGCGeomType(
443 std::string(eltType.get_utf8().value).c_str());
444 if( eGeomType != wkbUnknown )
445 {
446 int nIndex = m_poFeatureDefn->GetGeomFieldIndex(pszAttrName);
447 if( nIndex < 0 )
448 {
449 OGRGeomFieldDefn fldDefn( pszAttrName, eGeomType );
450 OGRSpatialReference* poSRS = new OGRSpatialReference();
451 poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
452 poSRS->SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
453 fldDefn.SetSpatialRef(poSRS);
454 poSRS->Release();
455 m_poFeatureDefn->AddGeomFieldDefn( &fldDefn );
456
457 aosPaths.push_back(std::string(elt.key()));
458 m_aaosGeomFieldPaths.push_back(aosPaths);
459 if( oMapIndices.find(pszAttrName) == oMapIndices.end() )
460 m_aosGeomIndexes.push_back(oMapIndices[pszAttrName]);
461 else
462 m_aosGeomIndexes.push_back("none");
463 m_apoCT.push_back(nullptr);
464 }
465 else
466 {
467 OGRGeomFieldDefn* poFDefn = m_poFeatureDefn->GetGeomFieldDefn(nIndex);
468 if( poFDefn->GetType() != eGeomType )
469 poFDefn->SetType(wkbUnknown);
470 }
471 }
472 }
473 else if( m_poDS->m_bFlattenNestedAttributes )
474 {
475 if( m_poFeatureDefn->GetGeomFieldIndex(pszAttrName) >= 0 )
476 return;
477 aosPaths.push_back(std::string(elt.key()));
478 for (auto&& subElt : doc)
479 {
480 char szSeparator[2];
481 szSeparator[0] = chNestedAttributeSeparator;
482 szSeparator[1] = 0;
483 CPLString osAttrName(pszAttrName);
484 osAttrName += szSeparator;
485 osAttrName += std::string(subElt.key());
486
487 std::vector<CPLString> aosNewPaths(aosPaths);
488 AddOrUpdateField(osAttrName, subElt,
489 chNestedAttributeSeparator,
490 aosNewPaths, oMapIndices);
491 }
492 return;
493 }
494 }
495 else if( eBSONType == bsoncxx::type::k_array )
496 {
497 if( m_poFeatureDefn->GetGeomFieldIndex(pszAttrName) >= 0 )
498 return;
499 if( oMapIndices.find(pszAttrName) != oMapIndices.end() &&
500 oMapIndices[pszAttrName] == "2d" )
501 {
502 OGRGeomFieldDefn fldDefn( pszAttrName, wkbPoint );
503 OGRSpatialReference* poSRS = new OGRSpatialReference();
504 poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
505 poSRS->SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
506 fldDefn.SetSpatialRef(poSRS);
507 poSRS->Release();
508 m_poFeatureDefn->AddGeomFieldDefn( &fldDefn );
509
510 aosPaths.push_back(std::string(elt.key()));
511 m_aaosGeomFieldPaths.push_back(aosPaths);
512 m_aosGeomIndexes.push_back("2d");
513 m_apoCT.push_back(nullptr);
514 }
515 }
516
517 if( m_poFeatureDefn->GetGeomFieldIndex(pszAttrName) >= 0 )
518 return;
519
520 OGRFieldSubType eNewSubType;
521 OGRFieldType eNewType = OGRMongoDBv3GetFieldTypeFromBSON( elt, eNewSubType );
522
523 int nIndex = m_poFeatureDefn->GetFieldIndex(pszAttrName);
524 if( nIndex < 0 )
525 {
526 OGRFieldDefn fldDefn( pszAttrName, eNewType );
527 fldDefn.SetSubType(eNewSubType);
528 if( eNewSubType == OFSTBoolean )
529 fldDefn.SetWidth(1);
530 m_poFeatureDefn->AddFieldDefn( &fldDefn );
531
532 aosPaths.push_back(std::string(elt.key()));
533 m_aaosFieldPaths.push_back(aosPaths);
534 }
535 else
536 {
537 OGRFieldDefn* poFDefn = m_poFeatureDefn->GetFieldDefn(nIndex);
538 OGRUpdateFieldType(poFDefn, eNewType, eNewSubType);
539 }
540 }
541
542 /************************************************************************/
543 /* CollectGeomIndices() */
544 /************************************************************************/
545
CollectGeomIndices()546 std::map< CPLString, CPLString> OGRMongoDBv3Layer::CollectGeomIndices()
547 {
548 std::map< CPLString, CPLString> oMapIndices;
549 try
550 {
551 auto cursor = m_oColl.list_indexes();
552 for (auto&& l_index : cursor)
553 {
554 //std::string s(bsoncxx::to_json(l_index));
555 //CPLDebug("MongoDBv3", "%s", s.c_str());
556 auto key = l_index["key"];
557 if( key && key.type() == bsoncxx::type::k_document )
558 {
559 bsoncxx::document::view keyDoc{key.get_document()};
560 for (auto&& field : keyDoc)
561 {
562 if( field.type() == bsoncxx::type::k_utf8 )
563 {
564 std::string v(field.get_utf8().value);
565 if( v == "2d" || v == "2dsphere" )
566 {
567 std::string idxColName(field.key());
568 //CPLDebug("MongoDBv3", "Index %s for %s of %s",
569 // v.c_str(),
570 // idxColName.c_str(),
571 // m_poFeatureDefn->GetName());
572 oMapIndices[idxColName] = v;
573 }
574 }
575 }
576 }
577 }
578 }
579 catch( const std::exception& ex )
580 {
581 CPLDebug("MongoDBv3", "Error when listing indices: %s", ex.what());
582 }
583 return oMapIndices;
584 }
585
586 /************************************************************************/
587 /* ReadOGRMetadata() */
588 /************************************************************************/
589
ReadOGRMetadata(std::map<CPLString,CPLString> & oMapIndices)590 bool OGRMongoDBv3Layer::ReadOGRMetadata(std::map< CPLString, CPLString>& oMapIndices)
591 {
592 try
593 {
594 bsoncxx::builder::basic::document filter{};
595 filter.append(kvp("layer", m_oColl.name()));
596 auto docOpt = m_oDb["_ogr_metadata"].find_one(filter.extract());
597 if( docOpt )
598 {
599 auto doc = docOpt->view();
600 auto fid = doc["fid"];
601 if( fid && fid.type() == bsoncxx::type::k_utf8 )
602 m_osFID = std::string(fid.get_utf8().value);
603
604 auto fields = doc["fields"];
605 if( fields && fields.type() == bsoncxx::type::k_array )
606 {
607 auto arrayView(fields.get_array().value);
608 for( const auto& elt: arrayView )
609 {
610 if( elt.type() == bsoncxx::type::k_document )
611 {
612 auto obj2_doc(elt.get_document());
613 auto obj2(obj2_doc.view());
614 auto name = obj2["name"];
615 auto type = obj2["type"];
616 auto subtype = obj2["subtype"];
617 auto path = obj2["path"];
618 if( name && name.type() == bsoncxx::type::k_utf8 &&
619 type && type.type() == bsoncxx::type::k_utf8 &&
620 path && path.type() == bsoncxx::type::k_array )
621 {
622 if( std::string(name.get_utf8().value) == "_id" )
623 continue;
624 OGRFieldType eType(OFTString);
625 for(int j=0; j<=OFTMaxType;j++)
626 {
627 if( EQUAL(OGR_GetFieldTypeName(static_cast<OGRFieldType>(j)),
628 std::string(type.get_utf8().value).c_str()) )
629 {
630 eType = static_cast<OGRFieldType>(j);
631 break;
632 }
633 }
634
635 std::vector<CPLString> aosPaths;
636 auto oPathArray(path.get_array().value);
637 bool ok = true;
638 for( const auto& eltPath: oPathArray )
639 {
640 if( eltPath.type() != bsoncxx::type::k_utf8 )
641 {
642 ok = false;
643 break;
644 }
645 aosPaths.push_back(std::string(eltPath.get_utf8().value));
646 }
647 if( !ok )
648 continue;
649
650 OGRFieldDefn oFieldDefn(std::string(name.get_utf8().value).c_str(), eType);
651 if( subtype && subtype.type() == bsoncxx::type::k_utf8 &&
652 std::string(subtype.get_utf8().value) == "Boolean" )
653 oFieldDefn.SetSubType(OFSTBoolean);
654 m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
655
656 m_aaosFieldPaths.push_back(aosPaths);
657 }
658 }
659 }
660 }
661
662 auto geomfields = doc["geomfields"];
663 if( geomfields && geomfields.type() == bsoncxx::type::k_array )
664 {
665 auto arrayView(geomfields.get_array().value);
666 for( const auto& elt: arrayView )
667 {
668 if( elt.type() == bsoncxx::type::k_document )
669 {
670 auto obj2_doc(elt.get_document());
671 auto obj2(obj2_doc.view());
672 auto name = obj2["name"];
673 auto type = obj2["type"];
674 auto path = obj2["path"];
675 if( name && name.type() == bsoncxx::type::k_utf8 &&
676 type && type.type() == bsoncxx::type::k_utf8 &&
677 path && path.type() == bsoncxx::type::k_array )
678 {
679
680 std::vector<CPLString> aosPaths;
681 auto oPathArray(path.get_array().value);
682 bool ok = true;
683 for( const auto& eltPath: oPathArray )
684 {
685 if( eltPath.type() != bsoncxx::type::k_utf8 )
686 {
687 ok = false;
688 break;
689 }
690 aosPaths.push_back(std::string(eltPath.get_utf8().value));
691 }
692 if( !ok )
693 continue;
694
695 OGRwkbGeometryType eType(OGRFromOGCGeomType(std::string(type.get_utf8().value).c_str()));
696 OGRGeomFieldDefn oFieldDefn(std::string(name.get_utf8().value).c_str(), eType);
697 OGRSpatialReference* poSRS = new OGRSpatialReference();
698 poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
699 poSRS->SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
700 oFieldDefn.SetSpatialRef(poSRS);
701 poSRS->Release();
702 m_poFeatureDefn->AddGeomFieldDefn(&oFieldDefn);
703
704 m_aaosGeomFieldPaths.push_back(aosPaths);
705 if( oMapIndices.find(oFieldDefn.GetNameRef()) != oMapIndices.end() )
706 m_aosGeomIndexes.push_back(oMapIndices[oFieldDefn.GetNameRef()]);
707 else
708 m_aosGeomIndexes.push_back("none");
709 //CPLDebug("MongoDBv3", "Layer %s: m_aosGeomIndexes[%d] = %s",
710 // m_poFeatureDefn->GetName(),
711 // m_poFeatureDefn->GetGeomFieldCount()-1,
712 // m_aosGeomIndexes[m_poFeatureDefn->GetGeomFieldCount()-1].c_str());
713 m_apoCT.push_back(nullptr);
714 }
715 }
716 }
717 }
718
719 m_bLayerMetadataUpdatable = true;
720 return true;
721 }
722 }
723 catch( const std::exception& ex )
724 {
725 CPLError(CE_Warning, CPLE_AppDefined, "%s: %s",
726 "ReadOGRMetadata()", ex.what());
727 }
728 return false;
729 }
730
731 /************************************************************************/
732 /* EstablishFeatureDefn() */
733 /************************************************************************/
734
EstablishFeatureDefn()735 void OGRMongoDBv3Layer::EstablishFeatureDefn()
736 {
737 if( m_bHasEstablishedFeatureDefn )
738 return;
739
740 std::map< CPLString, CPLString> oMapIndices(CollectGeomIndices());
741
742 int nCount = m_poDS->m_nFeatureCountToEstablishFeatureDefn;
743 if( m_poDS->m_bUseOGRMetadata )
744 {
745 if( ReadOGRMetadata(oMapIndices) )
746 nCount = 0;
747 }
748
749 if( nCount != 0 )
750 {
751 try
752 {
753 mongocxx::options::find options;
754 if( nCount > 0 )
755 {
756 options.limit(nCount);
757 }
758 if( m_poDS->m_nBatchSize > 0 )
759 {
760 options.batch_size(m_poDS->m_nBatchSize);
761 }
762
763 auto cursor = m_oColl.find({}, options);
764 for (auto&& doc : cursor)
765 {
766 //std::string s(bsoncxx::to_json(doc));
767 //CPLDebug("MongoDBv3", "%s", s.c_str());
768 for (auto&& field : doc)
769 {
770 std::vector<CPLString> aosPaths;
771 std::string osKey(field.key());
772 if( osKey == m_poDS->m_osFID )
773 {
774 m_osFID = osKey;
775 }
776 else
777 {
778 AddOrUpdateField(osKey.c_str(), field,
779 '.', aosPaths, oMapIndices);
780 }
781 }
782 }
783 }
784 catch( const std::exception& ex )
785 {
786 CPLError(CE_Failure, CPLE_AppDefined, "%s: %s",
787 "EstablishFeatureDefn()", ex.what());
788 }
789 }
790
791 if( m_poDS->m_bJSonField )
792 {
793 OGRFieldDefn fldDefn("_json", OFTString);
794 m_poFeatureDefn->AddFieldDefn( &fldDefn );
795 std::vector<CPLString> aosPaths;
796 m_aaosFieldPaths.push_back(aosPaths);
797 }
798
799 m_bHasEstablishedFeatureDefn = true;
800 }
801
802 /************************************************************************/
803 /* GetFIDColumn() */
804 /************************************************************************/
805
GetFIDColumn()806 const char* OGRMongoDBv3Layer::GetFIDColumn()
807 {
808 if( !m_bHasEstablishedFeatureDefn )
809 EstablishFeatureDefn();
810 return m_osFID.c_str();
811 }
812
813 /************************************************************************/
814 /* BuildQuery() */
815 /************************************************************************/
816
BuildQuery()817 bsoncxx::document::value OGRMongoDBv3Layer::BuildQuery()
818 {
819 bsoncxx::builder::basic::document b{};
820 auto queryAttrView(m_oQueryAttr.view());
821 for( const auto& field: queryAttrView )
822 {
823 b.append(kvp(field.key(), field.get_value()));
824 }
825 auto querySpatView(m_oQuerySpat.view());
826 for( const auto& field: querySpatView )
827 {
828 b.append(kvp(field.key(), field.get_value()));
829 }
830 return b.extract();
831 }
832
833 /************************************************************************/
834 /* GetFeatureCount() */
835 /************************************************************************/
836
GetFeatureCount(int bForce)837 GIntBig OGRMongoDBv3Layer::GetFeatureCount(int bForce)
838 {
839 if( m_poAttrQuery != nullptr ||
840 (m_poFilterGeom != nullptr && !TestCapability(OLCFastSpatialFilter)) )
841 {
842 return OGRLayer::GetFeatureCount(bForce);
843 }
844
845 if( !m_bHasEstablishedFeatureDefn )
846 EstablishFeatureDefn();
847 SyncToDisk();
848
849 try
850 {
851 return static_cast<GIntBig>(m_oColl.count_documents(BuildQuery()));
852 }
853 catch( const std::exception& ex )
854 {
855 CPLError(CE_Warning, CPLE_AppDefined, "%s: %s",
856 "GetFeatureCount()", ex.what());
857 return OGRLayer::GetFeatureCount(bForce);
858 }
859 }
860
861 /************************************************************************/
862 /* Stringify() */
863 /************************************************************************/
864
865 #if BSONCXX_VERSION_MAJOR > 3 || BSONCXX_VERSION_MINOR >= 6
Stringify(const bsoncxx::types::bson_value::view & val)866 static CPLString Stringify(const bsoncxx::types::bson_value::view& val)
867 #else
868 static CPLString Stringify(const bsoncxx::types::value& val)
869 #endif
870 {
871 const auto eBSONType = val.type();
872 if( eBSONType == bsoncxx::type::k_utf8 )
873 {
874 return std::string( val.get_utf8().value );
875 }
876 else if( eBSONType == bsoncxx::type::k_int32 )
877 return CPLSPrintf("%d", val.get_int32().value);
878 else if( eBSONType == bsoncxx::type::k_int64 )
879 return CPLSPrintf(CPL_FRMT_GIB, static_cast<GIntBig>(val.get_int64().value));
880 else if( eBSONType == bsoncxx::type::k_double )
881 return CPLSPrintf("%.16g", val.get_double().value);
882 else if( eBSONType == bsoncxx::type::k_oid )
883 return val.get_oid().value.to_string();
884 else if( eBSONType == bsoncxx::type::k_bool )
885 return CPLSPrintf("%d", val.get_bool().value);
886 else if( eBSONType == bsoncxx::type::k_date )
887 {
888 GIntBig secsandmillis = static_cast<GIntBig>(val.get_date().to_int64());
889 struct tm tm;
890 GIntBig secs = secsandmillis / 1000;
891 int millis = static_cast<int>(secsandmillis % 1000);
892 if( millis < 0 )
893 {
894 secs --;
895 millis += 1000;
896 }
897 CPLUnixTimeToYMDHMS(secs, &tm);
898 return CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
899 tm.tm_year + 1900,
900 tm.tm_mon + 1,
901 tm.tm_mday,
902 tm.tm_hour,
903 tm.tm_min,
904 tm.tm_sec,
905 millis);
906 }
907 else if( eBSONType == bsoncxx::type::k_document )
908 {
909 return CPLString(bsoncxx::to_json(val.get_document().value));
910 }
911 else
912 {
913 // This looks like a hack, but to_json() only works on documents
914 // so we have to wrap our value as a fake { "v": val } document...
915 bsoncxx::builder::basic::document b{};
916 b.append(kvp("v", val));
917 CPLString ret(bsoncxx::to_json(b.extract()));
918 CPLAssert(ret.find("{ \"v\" : ") == 0);
919 CPLAssert(ret.substr(ret.size() - 2) == " }");
920 ret = ret.substr(strlen("{ \"v\" : "), ret.size() - strlen("{ \"v\" : ") - 2);
921 return ret;
922 }
923 }
924
925 /************************************************************************/
926 /* OGRMongoDBV3ReaderSetField() */
927 /************************************************************************/
928
OGRMongoDBV3ReaderSetField(OGRFeature * poFeature,const char * pszAttrName,const bsoncxx::document::element & elt,bool bFlattenNestedAttributes,char chNestedAttributeSeparator)929 static void OGRMongoDBV3ReaderSetField(OGRFeature* poFeature,
930 const char* pszAttrName,
931 const bsoncxx::document::element& elt,
932 bool bFlattenNestedAttributes,
933 char chNestedAttributeSeparator)
934 {
935 int nGeomFieldIndex;
936 auto eBSONType = elt.type();
937
938 if( eBSONType == bsoncxx::type::k_document &&
939 (nGeomFieldIndex = poFeature->GetGeomFieldIndex(pszAttrName)) >= 0 )
940 {
941 CPLPushErrorHandler(CPLQuietErrorHandler);
942 OGRGeometry* poGeom = OGRGeometry::FromHandle(
943 OGR_G_CreateGeometryFromJson( Stringify(elt.get_value()) ));
944 CPLPopErrorHandler();
945 if( poGeom != nullptr )
946 {
947 poGeom->assignSpatialReference(
948 poFeature->GetDefnRef()->GetGeomFieldDefn(nGeomFieldIndex)->GetSpatialRef() );
949 poFeature->SetGeomFieldDirectly(nGeomFieldIndex, poGeom);
950 }
951 return;
952 }
953 else if( eBSONType == bsoncxx::type::k_array &&
954 (nGeomFieldIndex = poFeature->GetGeomFieldIndex(pszAttrName)) >= 0 )
955 {
956 auto arrayView = elt.get_array().value;
957 const unsigned nSize = static_cast<unsigned>(
958 std::distance(arrayView.begin(), arrayView.end()));
959 if( nSize == 2 )
960 {
961 auto x = arrayView[0];
962 auto y = arrayView[1];
963 if( x.type() == bsoncxx::type::k_double && y.type() == bsoncxx::type::k_double )
964 {
965 OGRGeometry* poGeom = new OGRPoint( x.get_double().value, y.get_double().value );
966 poGeom->assignSpatialReference(
967 poFeature->GetDefnRef()->GetGeomFieldDefn(nGeomFieldIndex)->GetSpatialRef() );
968 poFeature->SetGeomFieldDirectly(nGeomFieldIndex, poGeom);
969 }
970 }
971 return;
972 }
973
974 if( bFlattenNestedAttributes && eBSONType == bsoncxx::type::k_document )
975 {
976 auto doc(elt.get_document().value);
977 for (auto&& field : doc)
978 {
979 CPLString osAttrName(pszAttrName);
980 osAttrName += chNestedAttributeSeparator;
981 std::string keyName(field.key());
982 osAttrName += keyName;
983 OGRMongoDBV3ReaderSetField(poFeature,
984 osAttrName, field,
985 bFlattenNestedAttributes,
986 chNestedAttributeSeparator);
987 }
988 return ;
989 }
990
991 int nField = poFeature->GetFieldIndex(pszAttrName);
992 if( nField < 0 )
993 return;
994 OGRFieldDefn* poFieldDefn = poFeature->GetFieldDefnRef(nField);
995 CPLAssert( nullptr != poFieldDefn );
996 OGRFieldType eType = poFieldDefn->GetType();
997 if( eBSONType == bsoncxx::type::k_null )
998 poFeature->SetFieldNull( nField );
999 else if( eBSONType == bsoncxx::type::k_int32 )
1000 poFeature->SetField( nField, elt.get_int32().value );
1001 else if( eBSONType == bsoncxx::type::k_int64 )
1002 poFeature->SetField( nField, static_cast<GIntBig>(elt.get_int64().value) );
1003 else if( eBSONType == bsoncxx::type::k_double )
1004 poFeature->SetField( nField, elt.get_double().value );
1005 else if( eBSONType == bsoncxx::type::k_minkey && eType == OFTReal )
1006 poFeature->SetField( nField, -std::numeric_limits<double>::infinity() );
1007 else if( eBSONType == bsoncxx::type::k_maxkey && eType == OFTReal )
1008 poFeature->SetField( nField, std::numeric_limits<double>::infinity() );
1009 else if( eBSONType == bsoncxx::type::k_minkey && eType == OFTInteger )
1010 poFeature->SetField( nField, INT_MIN );
1011 else if( eBSONType == bsoncxx::type::k_maxkey && eType == OFTInteger )
1012 poFeature->SetField( nField, INT_MAX );
1013 else if( eBSONType == bsoncxx::type::k_minkey && eType == OFTInteger64 )
1014 poFeature->SetField( nField, std::numeric_limits<GIntBig>::min() );
1015 else if( eBSONType == bsoncxx::type::k_maxkey && eType == OFTInteger64 )
1016 poFeature->SetField( nField, std::numeric_limits<GIntBig>::max() );
1017 else if( eBSONType == bsoncxx::type::k_array )
1018 {
1019 auto arrayView = elt.get_array().value;
1020 const unsigned nSize = static_cast<unsigned>(
1021 std::distance(arrayView.begin(), arrayView.end()));
1022 if( eType == OFTStringList )
1023 {
1024 char** papszValues = static_cast<char**>(CPLCalloc(nSize + 1, sizeof(char*)));
1025 unsigned int i = 0;
1026 for( auto&& subElt : arrayView )
1027 {
1028 papszValues[i] = CPLStrdup(Stringify(subElt.get_value()));
1029 ++i;
1030 }
1031 poFeature->SetField( nField, papszValues );
1032 CSLDestroy(papszValues);
1033 }
1034 else if( eType == OFTRealList )
1035 {
1036 double* padfValues = static_cast<double*>(
1037 CPLMalloc(nSize * sizeof(double)));
1038 unsigned int i = 0;
1039 for( auto&& subElt : arrayView )
1040 {
1041 eBSONType = subElt.type();
1042 if( eBSONType == bsoncxx::type::k_int32 )
1043 padfValues[i] = subElt.get_int32().value;
1044 else if( eBSONType == bsoncxx::type::k_int64 )
1045 padfValues[i] = static_cast<double>(subElt.get_int64().value);
1046 else if( eBSONType == bsoncxx::type::k_double )
1047 padfValues[i] = subElt.get_double().value;
1048 else if( eBSONType == bsoncxx::type::k_minkey )
1049 padfValues[i] = -std::numeric_limits<double>::infinity();
1050 else if( eBSONType == bsoncxx::type::k_maxkey )
1051 padfValues[i] = std::numeric_limits<double>::infinity();
1052 else
1053 padfValues[i] = CPLAtof(Stringify(subElt.get_value()));
1054 ++i;
1055 }
1056 poFeature->SetField( nField, nSize, padfValues );
1057 CPLFree(padfValues);
1058 }
1059 else if( eType == OFTIntegerList )
1060 {
1061 int* panValues = static_cast<int*>(CPLMalloc(nSize * sizeof(int)));
1062 unsigned int i = 0;
1063 for( auto&& subElt : arrayView )
1064 {
1065 eBSONType = subElt.type();
1066 if( eBSONType == bsoncxx::type::k_int32 )
1067 panValues[i] = subElt.get_int32().value;
1068 else if( eBSONType == bsoncxx::type::k_int64 )
1069 {
1070 GIntBig nVal = subElt.get_int64().value;
1071 if( nVal < INT_MIN )
1072 panValues[i] = INT_MIN;
1073 else if( nVal > INT_MAX )
1074 panValues[i] = INT_MAX;
1075 else
1076 panValues[i] = static_cast<int>(nVal);
1077 }
1078 else if( eBSONType == bsoncxx::type::k_double )
1079 {
1080 double dfVal = subElt.get_double().value;
1081 if( dfVal < INT_MIN )
1082 panValues[i] = INT_MIN;
1083 else if( dfVal > INT_MAX )
1084 panValues[i] = INT_MAX;
1085 else
1086 panValues[i] = static_cast<int>(dfVal);
1087 }
1088 else if( eBSONType == bsoncxx::type::k_minkey )
1089 panValues[i] = INT_MIN;
1090 else if( eBSONType == bsoncxx::type::k_maxkey )
1091 panValues[i] = INT_MAX;
1092 else
1093 panValues[i] = atoi(Stringify(subElt.get_value()));
1094 ++i;
1095 }
1096 poFeature->SetField( nField, nSize, panValues );
1097 CPLFree(panValues);
1098 }
1099 else if( eType == OFTInteger64List )
1100 {
1101 GIntBig* panValues = static_cast<GIntBig*>(
1102 CPLMalloc(nSize * sizeof(GIntBig)));
1103 unsigned int i = 0;
1104 for( auto&& subElt : arrayView )
1105 {
1106 eBSONType = subElt.type();
1107 if( eBSONType == bsoncxx::type::k_int32 )
1108 panValues[i] = subElt.get_int32().value;
1109 else if( eBSONType == bsoncxx::type::k_int64 )
1110 panValues[i] = subElt.get_int64().value;
1111 else if( eBSONType == bsoncxx::type::k_double )
1112 {
1113 double dfVal = subElt.get_double().value;
1114 if( dfVal < std::numeric_limits<GIntBig>::min() )
1115 panValues[i] = std::numeric_limits<GIntBig>::min();
1116 else if( dfVal > static_cast<double>(std::numeric_limits<GIntBig>::max()) )
1117 panValues[i] = std::numeric_limits<GIntBig>::max();
1118 else
1119 panValues[i] = static_cast<GIntBig>(dfVal);
1120 }
1121 else if( eBSONType == bsoncxx::type::k_minkey )
1122 panValues[i] = std::numeric_limits<GIntBig>::min();
1123 else if( eBSONType == bsoncxx::type::k_maxkey )
1124 panValues[i] = std::numeric_limits<GIntBig>::max();
1125 else
1126 panValues[i] = CPLAtoGIntBig(Stringify(subElt.get_value()));
1127 ++i;
1128 }
1129 poFeature->SetField( nField, nSize, panValues );
1130 CPLFree(panValues);
1131 }
1132 }
1133 else if( eBSONType == bsoncxx::type::k_utf8 )
1134 {
1135 std::string s( elt.get_utf8().value );
1136 poFeature->SetField( nField, s.c_str() );
1137 }
1138 else if( eBSONType == bsoncxx::type::k_oid )
1139 poFeature->SetField( nField, elt.get_oid().value.to_string().c_str() );
1140 else if( eBSONType == bsoncxx::type::k_bool )
1141 poFeature->SetField( nField, elt.get_bool().value );
1142 else if( eBSONType == bsoncxx::type::k_binary )
1143 {
1144 const auto v(elt.get_binary());
1145 int len = static_cast<int>(v.size);
1146 const GByte *pabyData = v.bytes;
1147 poFeature->SetField( nField, len, pabyData);
1148 }
1149 else
1150 poFeature->SetField( nField, Stringify(elt.get_value()) );
1151 }
1152
1153 /************************************************************************/
1154 /* Translate() */
1155 /************************************************************************/
1156
Translate(const bsoncxx::document::view & doc)1157 std::unique_ptr<OGRFeature> OGRMongoDBv3Layer::Translate(
1158 const bsoncxx::document::view& doc)
1159 {
1160 std::unique_ptr<OGRFeature> poFeature(new OGRFeature(m_poFeatureDefn));
1161 for (auto&& field : doc)
1162 {
1163 std::string fieldName(field.key());
1164 if( !m_poDS->m_osFID.empty() && EQUAL(m_osFID, fieldName.c_str()) )
1165 {
1166 const auto eBSONType = field.type();
1167 if( eBSONType == bsoncxx::type::k_int32 )
1168 {
1169 poFeature->SetFID(field.get_int32().value);
1170 }
1171 else if( eBSONType == bsoncxx::type::k_int64 )
1172 {
1173 poFeature->SetFID(field.get_int64().value);
1174 }
1175 else if( eBSONType == bsoncxx::type::k_double )
1176 {
1177 double dfV = field.get_double().value;
1178 if( dfV >= static_cast<double>(
1179 std::numeric_limits<GIntBig>::min()) &&
1180 dfV <= static_cast<double>(
1181 std::numeric_limits<GIntBig>::max()) )
1182 {
1183 auto nV = static_cast<GIntBig>(dfV);
1184 if( static_cast<double>(nV) == dfV )
1185 {
1186 poFeature->SetFID(nV);
1187 }
1188 }
1189 }
1190 }
1191 else
1192 {
1193 OGRMongoDBV3ReaderSetField( poFeature.get(),
1194 fieldName.c_str(),
1195 field,
1196 m_poDS->m_bFlattenNestedAttributes,
1197 '.' );
1198 }
1199
1200 if( m_poDS->m_bJSonField )
1201 {
1202 poFeature->SetField("_json", bsoncxx::to_json(doc).c_str());
1203 }
1204 }
1205 return poFeature;
1206 }
1207
1208 /************************************************************************/
1209 /* GetNextFeature() */
1210 /************************************************************************/
1211
GetNextFeature()1212 OGRFeature* OGRMongoDBv3Layer::GetNextFeature()
1213 {
1214 if( !m_bHasEstablishedFeatureDefn )
1215 EstablishFeatureDefn();
1216 if( !m_aoDocsToInsert.empty() )
1217 SyncToDisk();
1218
1219 try
1220 {
1221 if( !m_poCursor )
1222 {
1223 mongocxx::options::find options;
1224 if( m_poDS->m_nBatchSize > 0 )
1225 {
1226 options.batch_size(m_poDS->m_nBatchSize);
1227 }
1228 m_poCursor.reset(new mongocxx::cursor(m_oColl.find(BuildQuery(), options)));
1229 m_poIterator.reset(new mongocxx::cursor::iterator(m_poCursor->begin()));
1230 }
1231 if( !m_poCursor || !m_poIterator )
1232 return nullptr;
1233
1234 while( *m_poIterator != m_poCursor->end() )
1235 {
1236 auto poFeature(Translate(**m_poIterator));
1237 if( poFeature->GetFID() < 0 )
1238 poFeature->SetFID(++m_nIndex);
1239
1240 (*m_poIterator) ++;
1241
1242 if((m_poFilterGeom == nullptr
1243 || FilterGeometry( poFeature->GetGeometryRef() ) )
1244 && (m_poAttrQuery == nullptr
1245 || m_poAttrQuery->Evaluate( poFeature.get() )) )
1246 {
1247 return poFeature.release();
1248 }
1249 }
1250 }
1251 catch( const std::exception& ex )
1252 {
1253 CPLError(CE_Failure, CPLE_AppDefined, "%s: %s",
1254 "GetNextFeature()", ex.what());
1255 }
1256 return nullptr;
1257 }
1258
1259 /************************************************************************/
1260 /* GetFeature() */
1261 /************************************************************************/
1262
GetFeature(GIntBig nFID)1263 OGRFeature* OGRMongoDBv3Layer::GetFeature(GIntBig nFID)
1264 {
1265 if( !m_bHasEstablishedFeatureDefn )
1266 EstablishFeatureDefn();
1267 if( !m_aoDocsToInsert.empty() )
1268 SyncToDisk();
1269
1270 if( m_osFID.empty() )
1271 {
1272 auto oQueryAttrBak = m_oQueryAttr;
1273 auto oQuerySpatBak = m_oQuerySpat;
1274 m_oQueryAttr = bsoncxx::builder::basic::make_document();
1275 m_oQuerySpat = bsoncxx::builder::basic::make_document();
1276 OGRFeature* poFeature = OGRLayer::GetFeature(nFID);
1277 m_oQueryAttr = oQueryAttrBak;
1278 m_oQuerySpat = oQuerySpatBak;
1279 return poFeature;
1280 }
1281
1282 try
1283 {
1284 bsoncxx::builder::basic::document b{};
1285 b.append( kvp( std::string(m_osFID), static_cast<int64_t>(nFID) ) );
1286 auto obj = m_oColl.find_one(b.extract());
1287 if( !obj )
1288 return nullptr;
1289
1290 auto poFeature = Translate(obj->view());
1291 poFeature->SetFID(nFID);
1292 return poFeature.release();
1293 }
1294 catch( const std::exception &ex )
1295 {
1296 CPLError(CE_Failure, CPLE_AppDefined, "%s: %s",
1297 "GetFeature()", ex.what());
1298 return nullptr;
1299 }
1300 }
1301
1302 /************************************************************************/
1303 /* DeleteFeature() */
1304 /************************************************************************/
1305
DeleteFeature(GIntBig nFID)1306 OGRErr OGRMongoDBv3Layer::DeleteFeature(GIntBig nFID)
1307 {
1308 if( m_poDS->GetAccess() != GA_Update )
1309 {
1310 CPLError(CE_Failure, CPLE_AppDefined, "Dataset opened in read-only mode");
1311 return OGRERR_FAILURE;
1312 }
1313
1314 if( !m_bHasEstablishedFeatureDefn )
1315 EstablishFeatureDefn();
1316 if( !m_aoDocsToInsert.empty() )
1317 SyncToDisk();
1318 if( m_osFID.empty() )
1319 return OGRERR_FAILURE;
1320
1321 try
1322 {
1323 bsoncxx::builder::basic::document b{};
1324 b.append( kvp( std::string(m_osFID), static_cast<int64_t>(nFID) ) );
1325 auto obj = m_oColl.find_one_and_delete(b.extract());
1326 //if( obj )
1327 //{
1328 // std::string s(bsoncxx::to_json(obj->view()));
1329 // CPLDebug("MongoDBv3", "%s", s.c_str());
1330 //}
1331 return obj ? OGRERR_NONE : OGRERR_NON_EXISTING_FEATURE;
1332 }
1333 catch( const std::exception &ex )
1334 {
1335 CPLError(CE_Failure, CPLE_AppDefined, "%s: %s",
1336 "DeleteFeature()", ex.what());
1337 return OGRERR_FAILURE;
1338 }
1339 }
1340
1341 /************************************************************************/
1342 /* CreateField() */
1343 /************************************************************************/
1344
CreateField(OGRFieldDefn * poFieldIn,int)1345 OGRErr OGRMongoDBv3Layer::CreateField( OGRFieldDefn *poFieldIn, int )
1346
1347 {
1348 if( m_poDS->GetAccess() != GA_Update )
1349 {
1350 CPLError(CE_Failure, CPLE_AppDefined, "Dataset opened in read-only mode");
1351 return OGRERR_FAILURE;
1352 }
1353
1354 const char* pszFieldName = poFieldIn->GetNameRef();
1355 if( m_poFeatureDefn->GetFieldIndex(pszFieldName) >= 0 )
1356 {
1357 if( !EQUAL(pszFieldName, "_id") &&
1358 !EQUAL(pszFieldName, "_json") )
1359 {
1360 CPLError(CE_Failure, CPLE_AppDefined,
1361 "CreateField() called with an already existing field name: %s",
1362 pszFieldName);
1363 }
1364 return OGRERR_FAILURE;
1365 }
1366
1367 m_poFeatureDefn->AddFieldDefn( poFieldIn );
1368
1369 std::vector<CPLString> aosPaths;
1370 if( m_bDotAsNestedField )
1371 {
1372 char** papszTokens = CSLTokenizeString2(pszFieldName, ".", 0);
1373 for(int i=0; papszTokens[i]; i++ )
1374 aosPaths.push_back(papszTokens[i]);
1375 CSLDestroy(papszTokens);
1376 }
1377 else
1378 aosPaths.push_back(pszFieldName);
1379 m_aaosFieldPaths.push_back(aosPaths);
1380
1381 m_bUpdateLayerMetadata = m_bLayerMetadataUpdatable;
1382
1383 return OGRERR_NONE;
1384 }
1385
1386 /************************************************************************/
1387 /* CreateGeomField() */
1388 /************************************************************************/
1389
CreateGeomField(OGRGeomFieldDefn * poFieldIn,int)1390 OGRErr OGRMongoDBv3Layer::CreateGeomField( OGRGeomFieldDefn *poFieldIn, int )
1391
1392 {
1393 if( m_poDS->GetAccess() != GA_Update )
1394 {
1395 CPLError(CE_Failure, CPLE_AppDefined, "Dataset opened in read-only mode");
1396 return OGRERR_FAILURE;
1397 }
1398
1399 if( m_poFeatureDefn->GetGeomFieldIndex(poFieldIn->GetNameRef()) >= 0 )
1400 {
1401 CPLError(CE_Failure, CPLE_AppDefined,
1402 "CreateGeomField() called with an already existing field name: %s",
1403 poFieldIn->GetNameRef());
1404 return OGRERR_FAILURE;
1405 }
1406
1407 OGRGeomFieldDefn oFieldDefn(poFieldIn);
1408 if( EQUAL(oFieldDefn.GetNameRef(), "") )
1409 oFieldDefn.SetName("geometry");
1410
1411 m_poFeatureDefn->AddGeomFieldDefn( &oFieldDefn );
1412
1413 std::vector<CPLString> aosPaths;
1414 if( m_bDotAsNestedField )
1415 {
1416 char** papszTokens = CSLTokenizeString2(oFieldDefn.GetNameRef(), ".", 0);
1417 for(int i=0; papszTokens[i]; i++ )
1418 aosPaths.push_back(papszTokens[i]);
1419 CSLDestroy(papszTokens);
1420 }
1421 else
1422 aosPaths.push_back(oFieldDefn.GetNameRef());
1423 m_aaosGeomFieldPaths.push_back(aosPaths);
1424 m_aosGeomIndexes.push_back("none");
1425
1426 std::unique_ptr<OGRCoordinateTransformation> poCT;
1427 if( oFieldDefn.GetSpatialRef() != nullptr )
1428 {
1429 OGRSpatialReference oSRS_WGS84;
1430 oSRS_WGS84.SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
1431 oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1432 if( !oSRS_WGS84.IsSame(oFieldDefn.GetSpatialRef()) )
1433 {
1434 poCT.reset(OGRCreateCoordinateTransformation( oFieldDefn.GetSpatialRef(), &oSRS_WGS84 ));
1435 if( poCT.get() == nullptr )
1436 {
1437 CPLError( CE_Warning, CPLE_AppDefined,
1438 "On-the-fly reprojection to WGS84 long/lat would be "
1439 "needed, but instantiation of transformer failed" );
1440 }
1441 }
1442 }
1443 m_apoCT.push_back(std::move(poCT));
1444
1445 if( m_bCreateSpatialIndex )
1446 {
1447 //CPLDebug("MongoDBv3", "Create spatial index for %s of %s",
1448 // poFieldIn->GetNameRef(), m_poFeatureDefn->GetName());
1449 try
1450 {
1451 const char* pszIndexType;
1452 if( wkbFlatten(poFieldIn->GetType()) != wkbPoint )
1453 pszIndexType = "2dsphere";
1454 else
1455 pszIndexType = CPLGetConfigOption("OGR_MONGODB_SPAT_INDEX_TYPE", "2dsphere");
1456
1457 bsoncxx::builder::basic::document b{};
1458 b.append(kvp(
1459 std::string(oFieldDefn.GetNameRef()),
1460 std::string(pszIndexType)));
1461 m_oColl.create_index(b.extract());
1462
1463 m_aosGeomIndexes.back() = pszIndexType;
1464 }
1465 catch( const std::exception &ex )
1466 {
1467 CPLError(CE_Failure, CPLE_AppDefined, "%s: %s",
1468 "Index creation", ex.what());
1469 }
1470 }
1471
1472 m_bUpdateLayerMetadata = m_bLayerMetadataUpdatable;
1473
1474 return OGRERR_NONE;
1475 }
1476
1477 /************************************************************************/
1478 /* SerializeField() */
1479 /************************************************************************/
1480
SerializeField(bsoncxx::builder::basic::document & b,OGRFeature * poFeature,int iField,const char * pszJSonField)1481 void OGRMongoDBv3Layer::SerializeField(bsoncxx::builder::basic::document& b,
1482 OGRFeature *poFeature,
1483 int iField,
1484 const char* pszJSonField)
1485 {
1486 OGRFieldType eType = m_poFeatureDefn->GetFieldDefn(iField)->GetType();
1487 std::string osFieldName(pszJSonField);
1488 if( poFeature->IsFieldNull(iField) )
1489 {
1490 b.append( kvp(osFieldName, bsoncxx::types::b_null{}) );
1491 }
1492 else if( eType == OFTInteger )
1493 {
1494 if( m_poFeatureDefn->GetFieldDefn(iField)->GetSubType() == OFSTBoolean )
1495 b.append( kvp(osFieldName, CPL_TO_BOOL(poFeature->GetFieldAsInteger(iField)) ));
1496 else
1497 b.append( kvp(osFieldName, poFeature->GetFieldAsInteger(iField) ));
1498 }
1499 else if( eType == OFTInteger64 )
1500 b.append( kvp(osFieldName, static_cast<int64_t>(
1501 poFeature->GetFieldAsInteger64(iField))) );
1502 else if( eType == OFTReal )
1503 b.append( kvp(osFieldName, poFeature->GetFieldAsDouble(iField) ));
1504 else if( eType == OFTString )
1505 b.append( kvp(osFieldName, poFeature->GetFieldAsString(iField) ));
1506 else if( eType == OFTStringList )
1507 {
1508 char** papszValues = poFeature->GetFieldAsStringList(iField);
1509 bsoncxx::builder::basic::array arrayBuilder;
1510 for(int i=0; papszValues[i]; i++)
1511 arrayBuilder.append( papszValues[i] );
1512 b.append( kvp(osFieldName, arrayBuilder.extract() ));
1513 }
1514 else if( eType == OFTIntegerList )
1515 {
1516 int nSize;
1517 const int* panValues = poFeature->GetFieldAsIntegerList(iField, &nSize);
1518 bsoncxx::builder::basic::array arrayBuilder;
1519 for(int i=0; i<nSize; i++)
1520 arrayBuilder.append( panValues[i] );
1521 b.append( kvp(osFieldName, arrayBuilder.extract() ));
1522 }
1523 else if( eType == OFTInteger64List )
1524 {
1525 int nSize;
1526 const GIntBig* panValues = poFeature->GetFieldAsInteger64List(iField, &nSize);
1527 bsoncxx::builder::basic::array arrayBuilder;
1528 for(int i=0; i<nSize; i++)
1529 arrayBuilder.append( static_cast<int64_t>(panValues[i]) );
1530 b.append( kvp(osFieldName, arrayBuilder.extract() ));
1531 }
1532 else if( eType == OFTRealList )
1533 {
1534 int nSize;
1535 const double* padfValues = poFeature->GetFieldAsDoubleList(iField, &nSize);
1536 bsoncxx::builder::basic::array arrayBuilder;
1537 for(int i=0; i<nSize; i++)
1538 arrayBuilder.append( padfValues[i] );
1539 b.append( kvp(osFieldName, arrayBuilder.extract() ));
1540 }
1541 else if( eType == OFTBinary )
1542 {
1543 int nSize;
1544 const GByte* pabyData = poFeature->GetFieldAsBinary(iField, &nSize);
1545 bsoncxx::types::b_binary bin;
1546 bin.sub_type = bsoncxx::binary_sub_type::k_binary;
1547 bin.size = nSize;
1548 bin.bytes = pabyData;
1549 b.append( kvp(osFieldName, bin) );
1550 }
1551 else if( eType == OFTDate || eType == OFTDateTime || eType == OFTTime )
1552 {
1553 struct tm tm;
1554 int nYear, nMonth, nDay, nHour, nMinute, nTZ;
1555 float fSecond;
1556 poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay,
1557 &nHour, &nMinute, &fSecond, &nTZ);
1558 tm.tm_year = nYear - 1900;
1559 tm.tm_mon = nMonth - 1;
1560 tm.tm_mday = nDay;
1561 tm.tm_hour = nHour;
1562 tm.tm_min = nMinute;
1563 tm.tm_sec = static_cast<int>(fSecond);
1564 GIntBig millis = 1000 * CPLYMDHMSToUnixTime(&tm) +
1565 static_cast<GIntBig>(1000 * fmod(fSecond, 1));
1566 b.append( kvp(osFieldName, bsoncxx::types::b_date(
1567 static_cast<std::chrono::milliseconds>(millis)) ) );
1568 }
1569 }
1570
1571 /************************************************************************/
1572 /* SerializeGeometry() */
1573 /************************************************************************/
1574
SerializeGeometry(bsoncxx::builder::basic::document & b,OGRGeometry * poGeom,int iField,const char * pszJSonField)1575 void OGRMongoDBv3Layer::SerializeGeometry(bsoncxx::builder::basic::document& b,
1576 OGRGeometry* poGeom, int iField,
1577 const char* pszJSonField)
1578 {
1579 std::string osFieldName(pszJSonField);
1580 if( m_aosGeomIndexes[iField] == "2d" &&
1581 wkbFlatten(poGeom->getGeometryType()) == wkbPoint )
1582 {
1583 bsoncxx::builder::basic::array arrayBuilder;
1584 OGRPoint* poPoint = poGeom->toPoint();
1585 arrayBuilder.append( poPoint->getX() );
1586 arrayBuilder.append( poPoint->getY() );
1587 b.append( kvp(osFieldName, arrayBuilder.extract()) );
1588 }
1589 else
1590 {
1591 char* pszJSon = OGR_G_ExportToJson(OGRGeometry::ToHandle(poGeom));
1592 if( pszJSon )
1593 {
1594 //CPLDebug("MongoDBv3", "%s", pszJSon);
1595 auto obj(bsoncxx::from_json(pszJSon));
1596 b.append( kvp(osFieldName, obj) );
1597 }
1598 CPLFree(pszJSon);
1599 }
1600 }
1601
1602 /************************************************************************/
1603 /* SerializeRecursive() */
1604 /************************************************************************/
1605
SerializeRecursive(bsoncxx::builder::basic::document & b,OGRFeature * poFeature,std::map<CPLString,IntOrMap * > & aoMap)1606 void OGRMongoDBv3Layer::SerializeRecursive(bsoncxx::builder::basic::document& b,
1607 OGRFeature *poFeature,
1608 std::map< CPLString, IntOrMap*>& aoMap )
1609 {
1610 std::map< CPLString, IntOrMap* >::iterator oIter = aoMap.begin();
1611 for( ; oIter != aoMap.end(); ++oIter)
1612 {
1613 IntOrMap* intOrMap = oIter->second;
1614 if( intOrMap->bIsMap )
1615 {
1616 bsoncxx::builder::basic::document subB;
1617 SerializeRecursive(subB, poFeature, *(intOrMap->u.poMap));
1618 b.append( kvp( std::string(oIter->first), subB.extract()) );
1619 delete intOrMap->u.poMap;
1620 }
1621 else
1622 {
1623 int i = intOrMap->u.nField;
1624 if( i >= 0)
1625 {
1626 SerializeField(b, poFeature, i, oIter->first.c_str());
1627 }
1628 else
1629 {
1630 i = -i - 1;
1631 OGRGeometry* poGeom = poFeature->GetGeomFieldRef(i);
1632 SerializeGeometry(b, poGeom, i, oIter->first.c_str());
1633 }
1634 }
1635 delete intOrMap;
1636 }
1637 }
1638
1639 /************************************************************************/
1640 /* InsertInMap() */
1641 /************************************************************************/
1642
InsertInMap(IntOrMap * rootMap,std::map<std::vector<CPLString>,IntOrMap * > & aoMap,const std::vector<CPLString> & aosFieldPathFull,int nField)1643 void OGRMongoDBv3Layer::InsertInMap(IntOrMap* rootMap,
1644 std::map< std::vector<CPLString>, IntOrMap*>& aoMap,
1645 const std::vector<CPLString>& aosFieldPathFull,
1646 int nField)
1647 {
1648 std::vector<CPLString> aosFieldPath;
1649 std::vector<CPLString> aosFieldPathPrev;
1650 for(int j=0; j< static_cast<int>(aosFieldPathFull.size()) - 1; j++)
1651 {
1652 aosFieldPath.push_back(aosFieldPathFull[j]);
1653 if( aoMap.find(aosFieldPath) == aoMap.end() )
1654 {
1655 IntOrMap* intOrMap = new IntOrMap;
1656 intOrMap->bIsMap = TRUE;
1657 intOrMap->u.poMap = new std::map< CPLString, IntOrMap*>;
1658 aoMap[aosFieldPath] = intOrMap;
1659 }
1660 if( j > 0 )
1661 {
1662 std::map< CPLString, IntOrMap* >* poPrevMap = aoMap[aosFieldPathPrev]->u.poMap;
1663 (*poPrevMap)[aosFieldPathFull[j]] = aoMap[aosFieldPath];
1664 }
1665 else
1666 (*(rootMap->u.poMap))[aosFieldPathFull[j]] = aoMap[aosFieldPath];
1667 aosFieldPathPrev.push_back(aosFieldPathFull[j]);
1668 }
1669 IntOrMap* intOrMap = new IntOrMap;
1670 intOrMap->bIsMap = FALSE;
1671 intOrMap->u.nField = nField;
1672 std::map< CPLString, IntOrMap* >* poPrevMap = aoMap[aosFieldPathPrev]->u.poMap;
1673 const CPLString& osLastComponent(aosFieldPathFull.back());
1674 CPLAssert( (*poPrevMap).find(osLastComponent) == (*poPrevMap).end() );
1675 (*(poPrevMap))[osLastComponent] = intOrMap;
1676 }
1677
1678 /************************************************************************/
1679 /* BuildBSONObjFromFeature() */
1680 /************************************************************************/
1681
BuildBSONObjFromFeature(OGRFeature * poFeature,bool bUpdate)1682 bsoncxx::document::value OGRMongoDBv3Layer::BuildBSONObjFromFeature(OGRFeature* poFeature, bool bUpdate)
1683 {
1684 bsoncxx::builder::basic::document b{};
1685
1686 int nJSonFieldIndex = m_poFeatureDefn->GetFieldIndex("_json");
1687 if( nJSonFieldIndex >= 0 && poFeature->IsFieldSetAndNotNull(nJSonFieldIndex) )
1688 {
1689 CPLString osJSon(poFeature->GetFieldAsString(nJSonFieldIndex));
1690
1691 auto obj(bsoncxx::from_json(osJSon));
1692 auto obj_view(obj.view());
1693 if( (m_bIgnoreSourceID || !obj_view["_id"]) && !bUpdate )
1694 {
1695 bsoncxx::oid generated;
1696 b.append(kvp("_id", generated));
1697 poFeature->SetField(0, generated.to_string().c_str());
1698 }
1699 for( const auto& field: obj_view )
1700 {
1701 b.append(kvp(field.key(), field.get_value()));
1702 }
1703 return b.extract();
1704 }
1705
1706 if( poFeature->GetFID() >= 0 && !m_osFID.empty() )
1707 {
1708 b.append(kvp( std::string(m_osFID),
1709 static_cast<int64_t>(poFeature->GetFID()) ));
1710 }
1711
1712 CPLAssert(static_cast<int>(m_aaosFieldPaths.size()) == m_poFeatureDefn->GetFieldCount());
1713
1714 if( !poFeature->IsFieldSetAndNotNull(0) || (!bUpdate && m_bIgnoreSourceID) )
1715 {
1716 bsoncxx::oid generated;
1717 b.append(kvp("_id", generated));
1718 poFeature->SetField(0, generated.to_string().c_str());
1719 }
1720 else
1721 b.append(kvp(
1722 "_id", bsoncxx::oid(poFeature->GetFieldAsString(0)) ));
1723
1724 IntOrMap* rootMap = new IntOrMap;
1725 rootMap->bIsMap = TRUE;
1726 rootMap->u.poMap = new std::map< CPLString, IntOrMap*>;
1727 std::map< std::vector<CPLString>, IntOrMap*> aoMap;
1728
1729 for(int i=1;i<m_poFeatureDefn->GetFieldCount();i++)
1730 {
1731 if( !poFeature->IsFieldSet(i) )
1732 continue;
1733
1734 if( m_aaosFieldPaths[i].size() > 1 )
1735 {
1736 InsertInMap(rootMap, aoMap, m_aaosFieldPaths[i], i);
1737 }
1738 else
1739 {
1740 const char* pszFieldName = m_poFeatureDefn->GetFieldDefn(i)->GetNameRef();
1741 SerializeField(b, poFeature, i, pszFieldName);
1742 }
1743 }
1744
1745 CPLAssert(static_cast<int>(m_aaosGeomFieldPaths.size()) == m_poFeatureDefn->GetGeomFieldCount());
1746 CPLAssert(static_cast<int>(m_apoCT.size()) == m_poFeatureDefn->GetGeomFieldCount());
1747 for(int i=0;i<m_poFeatureDefn->GetGeomFieldCount();i++)
1748 {
1749 OGRGeometry* poGeom = poFeature->GetGeomFieldRef(i);
1750 if( poGeom == nullptr )
1751 continue;
1752 if( !bUpdate && m_apoCT[i] != nullptr )
1753 poGeom->transform( m_apoCT[i].get() );
1754
1755 if( m_aaosGeomFieldPaths[i].size() > 1 )
1756 {
1757 InsertInMap(rootMap, aoMap, m_aaosGeomFieldPaths[i], -i-1);
1758 }
1759 else
1760 {
1761 const char* pszFieldName = m_poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef();
1762 SerializeGeometry(b, poGeom, i, pszFieldName);
1763 }
1764 }
1765
1766 SerializeRecursive(b, poFeature, *(rootMap->u.poMap));
1767 delete rootMap->u.poMap;
1768 delete rootMap;
1769
1770 return b.extract();
1771 }
1772
1773 /************************************************************************/
1774 /* ICreateFeature() */
1775 /************************************************************************/
1776
ICreateFeature(OGRFeature * poFeature)1777 OGRErr OGRMongoDBv3Layer::ICreateFeature( OGRFeature *poFeature )
1778 {
1779 if( m_poDS->GetAccess() != GA_Update )
1780 {
1781 CPLError(CE_Failure, CPLE_AppDefined, "Dataset opened in read-only mode");
1782 return OGRERR_FAILURE;
1783 }
1784
1785 if( !m_bHasEstablishedFeatureDefn )
1786 EstablishFeatureDefn();
1787
1788 try
1789 {
1790 if( poFeature->GetFID() < 0 )
1791 {
1792 if( m_nNextFID == 0 )
1793 m_nNextFID = GetFeatureCount(false);
1794 poFeature->SetFID(++m_nNextFID);
1795 }
1796
1797 auto bsonObj( BuildBSONObjFromFeature(poFeature, false) );
1798
1799 if( m_poDS->m_bBulkInsert )
1800 {
1801 constexpr size_t knMAX_DOCS_IN_BULK = 1000;
1802 if( m_aoDocsToInsert.size() == knMAX_DOCS_IN_BULK )
1803 SyncToDisk();
1804 m_aoDocsToInsert.emplace_back( std::move(bsonObj) );
1805 }
1806 else
1807 {
1808 //std::string s(bsoncxx::to_json(bsonObj));
1809 //CPLDebug("MongoDBv3", "%s", s.c_str());
1810 m_oColl.insert_one( std::move(bsonObj) );
1811 }
1812
1813 return OGRERR_NONE;
1814 }
1815 catch( const std::exception &ex )
1816 {
1817 CPLError(CE_Failure, CPLE_AppDefined, "%s: %s",
1818 "CreateFeature()", ex.what());
1819 return OGRERR_FAILURE;
1820 }
1821 }
1822
1823 /************************************************************************/
1824 /* ISetFeature() */
1825 /************************************************************************/
1826
ISetFeature(OGRFeature * poFeature)1827 OGRErr OGRMongoDBv3Layer::ISetFeature( OGRFeature *poFeature )
1828 {
1829 if( m_poDS->GetAccess() != GA_Update )
1830 {
1831 CPLError(CE_Failure, CPLE_AppDefined, "Dataset opened in read-only mode");
1832 return OGRERR_FAILURE;
1833 }
1834
1835 if( !m_bHasEstablishedFeatureDefn )
1836 EstablishFeatureDefn();
1837 if( !m_aoDocsToInsert.empty() )
1838 SyncToDisk();
1839
1840 if( !poFeature->IsFieldSetAndNotNull(0) )
1841 {
1842 CPLError(CE_Failure, CPLE_AppDefined, "_id field not set");
1843 return OGRERR_FAILURE;
1844 }
1845
1846 try
1847 {
1848 auto bsonObj( BuildBSONObjFromFeature(poFeature, true) );
1849 auto view(bsonObj.view());
1850
1851 bsoncxx::builder::basic::document filterBuilder{};
1852 filterBuilder.append( kvp("_id", view["_id"].get_oid().value ) );
1853 if( !m_osFID.empty() )
1854 filterBuilder.append( kvp( std::string(m_osFID),
1855 static_cast<int64_t>(poFeature->GetFID()) ) );
1856
1857 auto filter(filterBuilder.extract());
1858 auto ret = m_oColl.find_one_and_replace( std::move(filter), std::move(bsonObj) );
1859 //if( ret )
1860 //{
1861 // std::string s(bsoncxx::to_json(ret->view()));
1862 // CPLDebug("MongoDBv3", "%s", s.c_str());
1863 //}
1864 return ret ? OGRERR_NONE : OGRERR_NON_EXISTING_FEATURE;
1865 }
1866 catch( const std::exception &ex )
1867 {
1868 CPLError(CE_Failure, CPLE_AppDefined, "%s: %s",
1869 "SetFeature()", ex.what());
1870 return OGRERR_FAILURE;
1871 }
1872 }
1873 /************************************************************************/
1874 /* TestCapability() */
1875 /************************************************************************/
1876
TestCapability(const char * pszCap)1877 int OGRMongoDBv3Layer::TestCapability( const char* pszCap )
1878 {
1879 if( EQUAL(pszCap, OLCStringsAsUTF8) )
1880 {
1881 return true;
1882 }
1883 if( EQUAL(pszCap,OLCRandomRead) )
1884 {
1885 EstablishFeatureDefn();
1886 return !m_osFID.empty();
1887 }
1888 if( EQUAL(pszCap, OLCFastSpatialFilter) )
1889 {
1890 EstablishFeatureDefn();
1891 for(int i=0;i<m_poFeatureDefn->GetGeomFieldCount();i++)
1892 {
1893 if( m_aosGeomIndexes[i] == "none" )
1894 {
1895 return false;
1896 }
1897 }
1898 return true;
1899 }
1900 if( EQUAL(pszCap, OLCCreateField) ||
1901 EQUAL(pszCap, OLCCreateGeomField) ||
1902 EQUAL(pszCap, OLCSequentialWrite) ||
1903 EQUAL(pszCap, OLCRandomWrite) )
1904 {
1905 return m_poDS->GetAccess() == GA_Update;
1906 }
1907 else if( EQUAL(pszCap,OLCDeleteFeature) )
1908 {
1909 EstablishFeatureDefn();
1910 return m_poDS->GetAccess() == GA_Update &&
1911 !m_osFID.empty();
1912 }
1913
1914 return false;
1915 }
1916
1917 /************************************************************************/
1918 /* SetAttributeFilter() */
1919 /************************************************************************/
1920
SetAttributeFilter(const char * pszFilter)1921 OGRErr OGRMongoDBv3Layer::SetAttributeFilter(const char* pszFilter)
1922 {
1923 m_oQueryAttr = bsoncxx::builder::basic::make_document();
1924
1925 if( pszFilter != nullptr && pszFilter[0] == '{' )
1926 {
1927 OGRLayer::SetAttributeFilter(nullptr);
1928 try
1929 {
1930 m_oQueryAttr = bsoncxx::from_json(pszFilter);
1931 return OGRERR_NONE;
1932 }
1933 catch( const std::exception &ex )
1934 {
1935 CPLError(CE_Failure, CPLE_AppDefined, "%s: %s",
1936 "SetAttributeFilter()", ex.what());
1937 return OGRERR_FAILURE;
1938 }
1939 }
1940 return OGRLayer::SetAttributeFilter(pszFilter);
1941 }
1942
1943 /************************************************************************/
1944 /* SetSpatialFilter() */
1945 /************************************************************************/
1946
SetSpatialFilter(int iGeomField,OGRGeometry * poGeomIn)1947 void OGRMongoDBv3Layer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn )
1948
1949 {
1950 if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
1951 GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone )
1952 {
1953 if( iGeomField != 0 )
1954 {
1955 CPLError(CE_Failure, CPLE_AppDefined,
1956 "Invalid geometry field index : %d", iGeomField);
1957 }
1958 return;
1959 }
1960 m_iGeomFieldFilter = iGeomField;
1961
1962 m_oQuerySpat = bsoncxx::builder::basic::make_document();
1963 if( InstallFilter( poGeomIn ) && poGeomIn )
1964 {
1965 OGREnvelope sEnvelope;
1966 poGeomIn->getEnvelope(&sEnvelope);
1967 if( sEnvelope.MaxX == sEnvelope.MinX )
1968 sEnvelope.MaxX += 1e-10;
1969 if( sEnvelope.MaxY == sEnvelope.MinY )
1970 sEnvelope.MaxY += 1e-10;
1971
1972 if( sEnvelope.MinX < -180 )
1973 sEnvelope.MinX = -180;
1974 if( sEnvelope.MinY < -90 )
1975 sEnvelope.MinY = -90;
1976 if( sEnvelope.MaxX > 180 )
1977 sEnvelope.MaxX = 180;
1978 if( sEnvelope.MaxY > 90 )
1979 sEnvelope.MaxY = 90;
1980 if( sEnvelope.MinX == -180 && sEnvelope.MinY == -90 &&
1981 sEnvelope.MaxX == 180 && sEnvelope.MaxY == 90 )
1982 {
1983 return;
1984 }
1985
1986 try
1987 {
1988 if( m_aosGeomIndexes[m_iGeomFieldFilter] == "2dsphere" )
1989 {
1990 m_oQuerySpat = bsoncxx::from_json(CPLSPrintf("{ \"%s\" : { \"$geoIntersects\" : "
1991 "{ \"$geometry\" : { \"type\" : \"Polygon\" , \"coordinates\" : [["
1992 "[%.16g,%.16g],[%.16g,%.16g],[%.16g,%.16g],[%.16g,%.16g],[%.16g,%.16g]]] } } } }",
1993 m_poFeatureDefn->GetGeomFieldDefn(iGeomField)->GetNameRef(),
1994 sEnvelope.MinX, sEnvelope.MinY,
1995 sEnvelope.MaxX, sEnvelope.MinY,
1996 sEnvelope.MaxX, sEnvelope.MaxY,
1997 sEnvelope.MinX, sEnvelope.MaxY,
1998 sEnvelope.MinX, sEnvelope.MinY));
1999 }
2000 else if( m_aosGeomIndexes[m_iGeomFieldFilter] == "2d" )
2001 {
2002 m_oQuerySpat = bsoncxx::from_json(CPLSPrintf("{ \"%s\" : { \"$geoWithin\" : "
2003 "{ \"$box\" : [ [ %.16g , %.16g ] , [ %.16g , %.16g ] ] } } }",
2004 m_poFeatureDefn->GetGeomFieldDefn(iGeomField)->GetNameRef(),
2005 sEnvelope.MinX, sEnvelope.MinY,
2006 sEnvelope.MaxX, sEnvelope.MaxY));
2007 }
2008 }
2009 catch( const std::exception &ex )
2010 {
2011 CPLError(CE_Failure, CPLE_AppDefined,
2012 "%s: %s", "SetSpatialFilter()", ex.what());
2013 }
2014 }
2015 }
2016
2017 /************************************************************************/
2018 /* GetLayer() */
2019 /************************************************************************/
2020
GetLayer(int nIndex)2021 OGRLayer* OGRMongoDBv3Dataset::GetLayer(int nIndex)
2022 {
2023 if( nIndex < 0 || nIndex >= GetLayerCount() )
2024 return nullptr;
2025 return m_apoLayers[nIndex].get();
2026 }
2027
2028 /************************************************************************/
2029 /* GetLayerByName() */
2030 /************************************************************************/
2031
GetLayerByName(const char * pszLayerName)2032 OGRLayer *OGRMongoDBv3Dataset::GetLayerByName(const char* pszLayerName)
2033 {
2034 OGRLayer* poLayer = GDALDataset::GetLayerByName(pszLayerName);
2035 if( poLayer != nullptr )
2036 return poLayer;
2037
2038 for( const auto& l_poLayer: m_apoLayers )
2039 {
2040 l_poLayer->SyncToDisk();
2041 }
2042
2043 CPLString osDatabase;
2044 if( m_osDatabase.empty() )
2045 {
2046 const char* pszDot = strchr(pszLayerName, '.');
2047 if( pszDot == nullptr )
2048 return nullptr;
2049 osDatabase = pszLayerName;
2050 osDatabase.resize(pszDot - pszLayerName);
2051 pszLayerName = pszDot + 1;
2052 }
2053 else
2054 osDatabase = m_osDatabase;
2055
2056 for(int i=0;i<2;i++)
2057 {
2058 try
2059 {
2060 auto db = m_oConn.database(osDatabase);
2061 auto aosCollections = db.list_collection_names();
2062 for( const auto& osCollection: aosCollections )
2063 {
2064 if( EQUAL(osCollection.c_str(),pszLayerName) )
2065 {
2066 m_apoLayers.emplace_back(
2067 new OGRMongoDBv3Layer(this,
2068 osDatabase,
2069 osCollection.c_str()));
2070 return m_apoLayers.back().get();
2071 }
2072 }
2073 }
2074 catch( const std::exception &ex)
2075 {
2076 CPLError(CE_Failure, CPLE_AppDefined,
2077 "Command failed: %s", ex.what());
2078 }
2079 if( i == 0 )
2080 {
2081 if( m_osDatabase.empty() )
2082 break;
2083 const char* pszDot = strchr(pszLayerName, '.');
2084 if( pszDot == nullptr )
2085 break;
2086 osDatabase = pszLayerName;
2087 osDatabase.resize(pszDot - pszLayerName);
2088 pszLayerName = pszDot + 1;
2089 }
2090 }
2091
2092 return nullptr;
2093 }
2094
2095 /************************************************************************/
2096 /* CreateLayers() */
2097 /************************************************************************/
2098
CreateLayers(mongocxx::database & db)2099 void OGRMongoDBv3Dataset::CreateLayers(mongocxx::database& db)
2100 {
2101 std::string dbName(db.name());
2102 auto aosCollections = db.list_collection_names();
2103 for( const auto& osCollection: aosCollections )
2104 {
2105 if( osCollection != "_ogr_metadata" )
2106 {
2107 m_apoLayers.emplace_back(
2108 new OGRMongoDBv3Layer(this, dbName.c_str(), osCollection));
2109 }
2110 }
2111 }
2112
2113 /************************************************************************/
2114 /* Open() */
2115 /************************************************************************/
2116
Open(GDALOpenInfo * poOpenInfo)2117 bool OGRMongoDBv3Dataset::Open(GDALOpenInfo* poOpenInfo)
2118 {
2119 eAccess = poOpenInfo->eAccess;
2120
2121 const char* pszHost = CSLFetchNameValueDef(
2122 poOpenInfo->papszOpenOptions, "HOST", "localhost");
2123 const char* pszPort = CSLFetchNameValueDef(
2124 poOpenInfo->papszOpenOptions, "PORT", "27017");
2125 const char* pszURI = CSLFetchNameValue(
2126 poOpenInfo->papszOpenOptions, "URI");
2127 if( pszURI == nullptr )
2128 {
2129 if( STARTS_WITH_CI(poOpenInfo->pszFilename, "mongodbv3:") )
2130 pszURI = poOpenInfo->pszFilename + strlen("mongodbv3:");
2131 else if( STARTS_WITH_CI(poOpenInfo->pszFilename, "mongodb:") ||
2132 STARTS_WITH_CI(poOpenInfo->pszFilename, "mongodb+srv:") )
2133 pszURI = poOpenInfo->pszFilename;
2134 }
2135 const char* pszUser = CSLFetchNameValue(poOpenInfo->papszOpenOptions, "USER");
2136 const char* pszPassword = CSLFetchNameValue(poOpenInfo->papszOpenOptions, "PASSWORD");
2137 if( (pszUser != nullptr && pszPassword == nullptr) ||
2138 (pszUser == nullptr && pszPassword != nullptr) )
2139 {
2140 CPLError(CE_Failure, CPLE_AppDefined,
2141 "USER and PASSWORD open options must be both specified.");
2142 return false;
2143 }
2144
2145 try
2146 {
2147 mongocxx::uri uri;
2148 if( pszURI && pszURI[0] )
2149 {
2150 uri = mongocxx::uri(pszURI);
2151 }
2152 else
2153 {
2154 CPLString osURI("mongodb://");
2155 if( pszUser && pszPassword )
2156 {
2157 osURI += pszUser;
2158 osURI += ':';
2159 osURI += pszPassword;
2160 osURI += '@';
2161 }
2162 osURI += pszHost;
2163 osURI += ':';
2164 osURI += pszPort;
2165 uri = mongocxx::uri(osURI);
2166 }
2167 m_osDatabase = uri.database();
2168 if( m_osDatabase.empty() )
2169 {
2170 m_osDatabase = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "DBNAME", "");
2171 }
2172
2173 CPLString osPEMKeyFile = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "SSL_PEM_KEY_FILE", "");
2174 CPLString osPEMKeyPassword = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "SSL_PEM_KEY_PASSWORD", "");
2175 CPLString osCAFile = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "SSL_CA_FILE", "");
2176 CPLString osCRLFile = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "SSL_CRL_FILE", "");
2177 bool bAllowInvalidCertificates =
2178 CPLFetchBool(poOpenInfo->papszOpenOptions, "SSL_ALLOW_INVALID_CERTIFICATES", false);
2179
2180 mongocxx::options::client client_options;
2181 if( !osPEMKeyFile.empty() || !osPEMKeyPassword.empty() ||
2182 !osCAFile.empty() || !osCRLFile.empty() ||
2183 bAllowInvalidCertificates )
2184 {
2185 #if BSONCXX_VERSION_MAJOR > 3 || BSONCXX_VERSION_MINOR >= 6
2186 mongocxx::options::tls tls_options;
2187 #else
2188 mongocxx::options::ssl tls_options;
2189 #endif
2190 if( !osPEMKeyFile.empty() )
2191 tls_options.pem_file(osPEMKeyFile);
2192 if( !osPEMKeyPassword.empty() )
2193 tls_options.pem_password(osPEMKeyPassword);
2194 if( !osCAFile.empty() )
2195 tls_options.ca_file(osCAFile);
2196 if( !osCRLFile.empty() )
2197 tls_options.crl_file(osCRLFile);
2198 tls_options.allow_invalid_certificates(bAllowInvalidCertificates);
2199 #if BSONCXX_VERSION_MAJOR > 3 || BSONCXX_VERSION_MINOR >= 6
2200 client_options.tls_opts(tls_options);
2201 #else
2202 client_options.ssl_opts(tls_options);
2203 #endif
2204 }
2205
2206 m_oConn = mongocxx::client(uri, client_options);
2207
2208 try
2209 {
2210 auto db = m_oConn[m_osDatabase.empty() ? "admin" : m_osDatabase.c_str()];
2211 auto ret = db.run_command(bsoncxx::from_json("{ \"buildInfo\" : 1 }"));
2212 std::string s(bsoncxx::to_json(ret.view()));
2213 CPLDebug("MongoDBv3", "%s", s.c_str());
2214 }
2215 catch (const std::exception& ex)
2216 {
2217 CPLDebug("MongoDBv3", "buildInfo(): %s", ex.what());
2218 }
2219
2220 if( m_osDatabase.empty() )
2221 {
2222 auto dbs = m_oConn.list_databases();
2223 for( const auto& dbBson: dbs )
2224 {
2225 std::string dbName(dbBson["name"].get_utf8().value);
2226 if( dbName == "admin" || dbName == "config" || dbName == "local" )
2227 {
2228 continue;
2229 }
2230 CPLDebug("MongoDBv3", "Iterating over database %s", dbName.c_str() );
2231 auto db = m_oConn.database(dbName);
2232 CreateLayers(db);
2233 }
2234 }
2235 else
2236 {
2237 auto db = m_oConn.database(m_osDatabase);
2238 CreateLayers(db);
2239 }
2240 }
2241 catch (const std::exception& ex)
2242 {
2243 CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
2244 return false;
2245 }
2246
2247 m_nBatchSize = atoi(CSLFetchNameValueDef(
2248 poOpenInfo->papszOpenOptions, "BATCH_SIZE", "0"));
2249 m_nFeatureCountToEstablishFeatureDefn = atoi(CSLFetchNameValueDef(
2250 poOpenInfo->papszOpenOptions, "FEATURE_COUNT_TO_ESTABLISH_FEATURE_DEFN", "100"));
2251 m_bJSonField = CPLFetchBool(
2252 poOpenInfo->papszOpenOptions, "JSON_FIELD", false);
2253 m_bFlattenNestedAttributes =
2254 CPLFetchBool(poOpenInfo->papszOpenOptions, "FLATTEN_NESTED_ATTRIBUTES", true);
2255 m_osFID = CSLFetchNameValueDef(
2256 poOpenInfo->papszOpenOptions, "FID", "ogc_fid");
2257 m_bUseOGRMetadata =
2258 CPLFetchBool( poOpenInfo->papszOpenOptions, "USE_OGR_METADATA", true);
2259 m_bBulkInsert = CPLFetchBool(
2260 poOpenInfo->papszOpenOptions, "BULK_INSERT", true);
2261
2262 return true;
2263 }
2264
2265 /************************************************************************/
2266 /* ICreateLayer() */
2267 /************************************************************************/
2268
ICreateLayer(const char * pszName,OGRSpatialReference * poSpatialRef,OGRwkbGeometryType eGType,char ** papszOptions)2269 OGRLayer* OGRMongoDBv3Dataset::ICreateLayer( const char *pszName,
2270 OGRSpatialReference *poSpatialRef,
2271 OGRwkbGeometryType eGType,
2272 char ** papszOptions )
2273 {
2274 if( m_osDatabase.empty() )
2275 {
2276 CPLError(CE_Failure, CPLE_AppDefined,
2277 "Cannot create layer/collection when dataset opened without explicit database");
2278 return nullptr;
2279 }
2280
2281 if( eAccess != GA_Update )
2282 {
2283 CPLError(CE_Failure, CPLE_AppDefined, "Dataset opened in read-only mode");
2284 return nullptr;
2285 }
2286
2287 for(int i=0; i<static_cast<int>(m_apoLayers.size()); i++)
2288 {
2289 if( EQUAL(m_apoLayers[i]->GetName(), pszName) )
2290 {
2291 if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != nullptr
2292 && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
2293 {
2294 DeleteLayer( i );
2295 }
2296 else
2297 {
2298 CPLError( CE_Failure, CPLE_AppDefined,
2299 "Layer %s already exists, CreateLayer failed.\n"
2300 "Use the layer creation option OVERWRITE=YES to "
2301 "replace it.",
2302 pszName );
2303 return nullptr;
2304 }
2305 }
2306 }
2307
2308 try
2309 {
2310 m_oConn[m_osDatabase].create_collection(std::string(pszName));
2311 }
2312 catch( const std::exception& ex)
2313 {
2314 CPLError(CE_Failure, CPLE_AppDefined, "%s", ex.what());
2315 return nullptr;
2316 }
2317
2318 m_apoLayers.emplace_back(
2319 new OGRMongoDBv3Layer(this, m_osDatabase, pszName));
2320 auto poLayer = m_apoLayers.back().get();
2321
2322 poLayer->m_osFID = CSLFetchNameValueDef(papszOptions, "FID", "ogc_fid");
2323 poLayer->m_bLayerMetadataUpdatable =
2324 CPLFetchBool(papszOptions, "WRITE_OGR_METADATA", true);
2325 poLayer->m_bUpdateLayerMetadata = poLayer->m_bLayerMetadataUpdatable;
2326 poLayer->m_bDotAsNestedField =
2327 CPLFetchBool(papszOptions, "DOT_AS_NESTED_FIELD", true);
2328 poLayer->m_bIgnoreSourceID =
2329 CPLFetchBool(papszOptions, "IGNORE_SOURCE_ID", false);
2330 poLayer->m_bCreateSpatialIndex =
2331 CPLFetchBool(papszOptions, "SPATIAL_INDEX", true);
2332
2333 if( eGType != wkbNone )
2334 {
2335 const char* pszGeometryName = CSLFetchNameValueDef(papszOptions, "GEOMETRY_NAME", "geometry");
2336 OGRGeomFieldDefn oFieldDefn(pszGeometryName, eGType);
2337 oFieldDefn.SetSpatialRef(poSpatialRef);
2338 poLayer->CreateGeomField(&oFieldDefn, FALSE);
2339 }
2340
2341 return poLayer;
2342 }
2343
2344 /************************************************************************/
2345 /* DeleteLayer() */
2346 /************************************************************************/
2347
DeleteLayer(int iLayer)2348 OGRErr OGRMongoDBv3Dataset::DeleteLayer( int iLayer )
2349
2350 {
2351 if( eAccess != GA_Update )
2352 {
2353 CPLError(CE_Failure, CPLE_AppDefined, "Dataset opened in read-only mode");
2354 return OGRERR_FAILURE;
2355 }
2356
2357 if( iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()) )
2358 return OGRERR_FAILURE;
2359
2360 /* -------------------------------------------------------------------- */
2361 /* Blow away our OGR structures related to the layer. This is */
2362 /* pretty dangerous if anything has a reference to this layer! */
2363 /* -------------------------------------------------------------------- */
2364 CPLString osLayerName = m_apoLayers[iLayer]->GetName();
2365 CPLDebug( "MongoDB", "DeleteLayer(%s)", osLayerName.c_str() );
2366
2367 try
2368 {
2369 {
2370 bsoncxx::builder::basic::document b{};
2371 std::string colName(m_apoLayers[iLayer]->m_oColl.name());
2372 b.append(kvp("layer", colName));
2373 m_apoLayers[iLayer]->m_oDb["_ogr_metadata"].find_one_and_delete(b.extract());
2374 }
2375
2376 m_apoLayers[iLayer]->m_oColl.drop();
2377
2378 m_apoLayers.erase( m_apoLayers.begin() + iLayer );
2379
2380 return OGRERR_NONE;
2381 }
2382 catch( const std::exception &ex)
2383 {
2384 CPLError(CE_Failure, CPLE_AppDefined, "%s: %s",
2385 "DeleteLayer()", ex.what());
2386 return OGRERR_FAILURE;
2387 }
2388 }
2389
2390 /************************************************************************/
2391 /* TestCapability() */
2392 /************************************************************************/
2393
TestCapability(const char * pszCap)2394 int OGRMongoDBv3Dataset::TestCapability( const char * pszCap )
2395
2396 {
2397 if( EQUAL(pszCap,ODsCCreateLayer)
2398 || EQUAL(pszCap,ODsCDeleteLayer)
2399 || EQUAL(pszCap,ODsCCreateGeomFieldAfterCreateLayer) )
2400 return eAccess == GA_Update;
2401 else
2402 return FALSE;
2403 }
2404
2405 /************************************************************************/
2406 /* OGRMongoDBv3SingleFeatureLayer */
2407 /************************************************************************/
2408
2409 class OGRMongoDBv3SingleFeatureLayer final: public OGRLayer
2410 {
2411 OGRFeatureDefn *m_poFeatureDefn;
2412 CPLString osVal;
2413 int iNextShapeId;
2414 public:
2415 explicit OGRMongoDBv3SingleFeatureLayer( const char *pszVal );
~OGRMongoDBv3SingleFeatureLayer()2416 ~OGRMongoDBv3SingleFeatureLayer() { m_poFeatureDefn->Release(); }
ResetReading()2417 void ResetReading() override { iNextShapeId = 0; }
2418 OGRFeature *GetNextFeature() override;
GetLayerDefn()2419 OGRFeatureDefn *GetLayerDefn() override { return m_poFeatureDefn; }
TestCapability(const char *)2420 int TestCapability( const char * ) override { return FALSE; }
2421 };
2422
2423 /************************************************************************/
2424 /* OGRMongoDBv3SingleFeatureLayer() */
2425 /************************************************************************/
2426
OGRMongoDBv3SingleFeatureLayer(const char * pszVal)2427 OGRMongoDBv3SingleFeatureLayer::OGRMongoDBv3SingleFeatureLayer( const char *pszVal )
2428 {
2429 m_poFeatureDefn = new OGRFeatureDefn( "RESULT" );
2430 m_poFeatureDefn->Reference();
2431 OGRFieldDefn oField( "_json", OFTString );
2432 m_poFeatureDefn->AddFieldDefn( &oField );
2433
2434 iNextShapeId = 0;
2435 osVal = pszVal;
2436 }
2437
2438 /************************************************************************/
2439 /* GetNextFeature() */
2440 /************************************************************************/
2441
GetNextFeature()2442 OGRFeature * OGRMongoDBv3SingleFeatureLayer::GetNextFeature()
2443 {
2444 if (iNextShapeId != 0)
2445 return nullptr;
2446
2447 OGRFeature* poFeature = new OGRFeature(m_poFeatureDefn);
2448 poFeature->SetField(0, osVal);
2449 poFeature->SetFID(iNextShapeId ++);
2450 return poFeature;
2451 }
2452
2453 /************************************************************************/
2454 /* ExecuteSQL() */
2455 /************************************************************************/
2456
ExecuteSQL(const char * pszSQLCommand,OGRGeometry * poSpatialFilter,const char * pszDialect)2457 OGRLayer* OGRMongoDBv3Dataset::ExecuteSQL( const char *pszSQLCommand,
2458 OGRGeometry *poSpatialFilter,
2459 const char *pszDialect )
2460 {
2461 for( const auto& poLayer: m_apoLayers )
2462 {
2463 poLayer->SyncToDisk();
2464 }
2465
2466 /* -------------------------------------------------------------------- */
2467 /* Special case DELLAYER: command. */
2468 /* -------------------------------------------------------------------- */
2469 if( STARTS_WITH_CI(pszSQLCommand, "DELLAYER:") )
2470 {
2471 const char *pszLayerName = pszSQLCommand + 9;
2472
2473 while( *pszLayerName == ' ' )
2474 pszLayerName++;
2475
2476 for( int iLayer = 0; iLayer < static_cast<int>(m_apoLayers.size()); iLayer++ )
2477 {
2478 if( EQUAL(m_apoLayers[iLayer]->GetName(),
2479 pszLayerName ))
2480 {
2481 DeleteLayer( iLayer );
2482 break;
2483 }
2484 }
2485 return nullptr;
2486 }
2487
2488 /* -------------------------------------------------------------------- */
2489 /* Special case WRITE_OGR_METADATA command. */
2490 /* -------------------------------------------------------------------- */
2491 if( STARTS_WITH_CI(pszSQLCommand, "WRITE_OGR_METADATA ") )
2492 {
2493 if( eAccess != GA_Update )
2494 {
2495 CPLError(CE_Failure, CPLE_AppDefined, "Dataset opened in read-only mode");
2496 return nullptr;
2497 }
2498 const char* pszLayerName = pszSQLCommand + strlen("WRITE_OGR_METADATA ");
2499 auto poLayer = static_cast<OGRMongoDBv3Layer*>(GetLayerByName(pszLayerName));
2500 if( poLayer == nullptr )
2501 {
2502 CPLError(CE_Failure, CPLE_AppDefined, "Layer %s not found", pszLayerName);
2503 return nullptr;
2504 }
2505 poLayer->GetLayerDefn(); // force schema discovery
2506 poLayer->m_bLayerMetadataUpdatable = true;
2507 poLayer->m_bUpdateLayerMetadata = true;
2508 poLayer->SyncToDisk();
2509
2510 return nullptr;
2511 }
2512
2513 if( pszDialect != nullptr && EQUAL(pszDialect, "MONGODB") )
2514 {
2515 if( m_osDatabase.empty() )
2516 {
2517 CPLError(CE_Failure, CPLE_AppDefined,
2518 "Cannot run ExecuteSQL() when dataset opened without explicit database");
2519 return nullptr;
2520 }
2521 try
2522 {
2523 auto ret = m_oConn[m_osDatabase].run_command(bsoncxx::from_json(pszSQLCommand));
2524 return new OGRMongoDBv3SingleFeatureLayer(bsoncxx::to_json(ret).c_str());
2525 }
2526 catch( const std::exception &ex)
2527 {
2528 CPLError(CE_Failure, CPLE_AppDefined,
2529 "Command failed: %s", ex.what());
2530 return nullptr;
2531 }
2532 }
2533 else
2534 {
2535 return GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter, pszDialect);
2536 }
2537 }
2538
2539 /************************************************************************/
2540 /* ReleaseResultSet() */
2541 /************************************************************************/
2542
ReleaseResultSet(OGRLayer * poLayer)2543 void OGRMongoDBv3Dataset::ReleaseResultSet( OGRLayer * poLayer )
2544 {
2545 delete poLayer;
2546 }
2547
2548 /************************************************************************/
2549 /* OGRMongoDBv3DriverIdentify() */
2550 /************************************************************************/
2551
OGRMongoDBv3DriverIdentify(GDALOpenInfo * poOpenInfo)2552 static int OGRMongoDBv3DriverIdentify( GDALOpenInfo* poOpenInfo )
2553
2554 {
2555 return STARTS_WITH_CI(poOpenInfo->pszFilename, "MongoDBv3:") ||
2556 STARTS_WITH_CI(poOpenInfo->pszFilename, "mongodb+srv:") ||
2557 (STARTS_WITH_CI(poOpenInfo->pszFilename, "mongodb:") &&
2558 GDALGetDriverByName("MONGODB") == nullptr);
2559 }
2560
2561 /************************************************************************/
2562 /* OGRMongoDBv3DriverOpen() */
2563 /************************************************************************/
2564
OGRMongoDBv3DriverOpen(GDALOpenInfo * poOpenInfo)2565 static GDALDataset* OGRMongoDBv3DriverOpen( GDALOpenInfo* poOpenInfo )
2566
2567 {
2568 if( !OGRMongoDBv3DriverIdentify(poOpenInfo) )
2569 return nullptr;
2570
2571 {
2572 static std::mutex oMutex;
2573 std::lock_guard<std::mutex> oLock(oMutex);
2574 if( g_pInst == nullptr )
2575 {
2576 if( !g_bCanInstantiateMongo )
2577 {
2578 CPLError(CE_Failure, CPLE_AppDefined,
2579 "MongoDB client has been previously shut down and "
2580 "can no longer be reinitialized");
2581 return nullptr;
2582 }
2583
2584 #ifdef use_logger
2585 class logger final : public mongocxx::logger
2586 {
2587 public:
2588 explicit logger() {}
2589
2590 void operator()(mongocxx::log_level level,
2591 bsoncxx::stdx::string_view /*domain*/,
2592 bsoncxx::stdx::string_view message) noexcept override {
2593 if (level >= mongocxx::log_level::k_trace)
2594 return;
2595 std::string tmp(message);
2596 CPLDebug("MongoDBv3", "%s", tmp.c_str());
2597 }
2598 };
2599 #endif
2600 g_pInst = new mongocxx::instance(
2601 #ifdef use_logger
2602 bsoncxx::stdx::make_unique<logger>()
2603 #endif
2604 );
2605 }
2606 }
2607
2608 auto poDS = new OGRMongoDBv3Dataset();
2609 if( !poDS->Open(poOpenInfo) )
2610 {
2611 delete poDS;
2612 poDS = nullptr;
2613 }
2614
2615 return poDS;
2616 }
2617
2618 /************************************************************************/
2619 /* OGRMongoDBv3DriverUnload() */
2620 /************************************************************************/
2621
2622 extern "C" int GDALIsInGlobalDestructor();
2623
OGRMongoDBv3DriverUnload(GDALDriver *)2624 static void OGRMongoDBv3DriverUnload( GDALDriver* )
2625 {
2626 if( g_pInst != nullptr && !GDALIsInGlobalDestructor() )
2627 {
2628 delete g_pInst;
2629 g_pInst = nullptr;
2630 g_bCanInstantiateMongo = false;
2631 }
2632 }
2633 /************************************************************************/
2634 /* RegisterOGRMongoDBv3() */
2635 /************************************************************************/
2636
RegisterOGRMongoDBv3()2637 void RegisterOGRMongoDBv3()
2638 {
2639 if( GDALGetDriverByName( "MongoDBv3" ) != nullptr )
2640 return;
2641
2642 GDALDriver *poDriver = new GDALDriver();
2643
2644 poDriver->SetDescription( "MongoDBv3" );
2645 poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
2646 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "MongoDB (using libmongocxx v3 client)" );
2647 poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/vector/mongodbv3.html" );
2648
2649 poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "MongoDBv3:" );
2650
2651 poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
2652 "<LayerCreationOptionList>"
2653 " <Option name='OVERWRITE' type='boolean' description='Whether to overwrite an existing collection with the layer name to be created' default='NO'/>"
2654 " <Option name='GEOMETRY_NAME' type='string' description='Name of geometry column.' default='geometry'/>"
2655 " <Option name='SPATIAL_INDEX' type='boolean' description='Whether to create a spatial index' default='YES'/>"
2656 " <Option name='FID' type='string' description='Field name, with integer values, to use as FID' default='ogc_fid'/>"
2657 " <Option name='WRITE_OGR_METADATA' type='boolean' description='Whether to create a description of layer fields in the _ogr_metadata collection' default='YES'/>"
2658 " <Option name='DOT_AS_NESTED_FIELD' type='boolean' description='Whether to consider dot character in field name as sub-document' default='YES'/>"
2659 " <Option name='IGNORE_SOURCE_ID' type='boolean' description='Whether to ignore _id field in features passed to CreateFeature()' default='NO'/>"
2660 "</LayerCreationOptionList>");
2661
2662 poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
2663 "<OpenOptionList>"
2664 " <Option name='URI' type='string' description='Connection URI' />"
2665 " <Option name='HOST' type='string' description='Server hostname' />"
2666 " <Option name='PORT' type='integer' description='Server port' />"
2667 " <Option name='DBNAME' type='string' description='Database name' />"
2668 " <Option name='USER' type='string' description='User name' />"
2669 " <Option name='PASSWORD' type='string' description='User password' />"
2670 " <Option name='SSL_PEM_KEY_FILE' type='string' description='SSL PEM certificate/key filename' />"
2671 " <Option name='SSL_PEM_KEY_PASSWORD' type='string' description='SSL PEM key password' />"
2672 " <Option name='SSL_CA_FILE' type='string' description='SSL Certification Authority filename' />"
2673 " <Option name='SSL_CRL_FILE' type='string' description='SSL Certification Revocation List filename' />"
2674 " <Option name='SSL_ALLOW_INVALID_CERTIFICATES' type='boolean' description='Whether to allow connections to servers with invalid certificates' default='NO'/>"
2675 " <Option name='BATCH_SIZE' type='integer' description='Number of features to retrieve per batch'/>"
2676 " <Option name='FEATURE_COUNT_TO_ESTABLISH_FEATURE_DEFN' type='integer' description='Number of features to retrieve to establish feature definition. -1 = unlimited' default='100'/>"
2677 " <Option name='JSON_FIELD' type='boolean' description='Whether to include a field with the full document as JSON' default='NO'/>"
2678 " <Option name='FLATTEN_NESTED_ATTRIBUTES' type='boolean' description='Whether to recursively explore nested objects and produce flatten OGR attributes' default='YES'/>"
2679 " <Option name='FID' type='string' description='Field name, with integer values, to use as FID' default='ogc_fid'/>"
2680 " <Option name='USE_OGR_METADATA' type='boolean' description='Whether to use the _ogr_metadata collection to read layer metadata' default='YES'/>"
2681 " <Option name='BULK_INSERT' type='boolean' description='Whether to use bulk insert for feature creation' default='YES'/>"
2682 "</OpenOptionList>");
2683
2684 poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime Time IntegerList Integer64List RealList StringList Binary" );
2685 poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATASUBTYPES, "Boolean" );
2686
2687 poDriver->pfnOpen = OGRMongoDBv3DriverOpen;
2688 poDriver->pfnIdentify = OGRMongoDBv3DriverIdentify;
2689 poDriver->pfnUnloadDriver = OGRMongoDBv3DriverUnload;
2690
2691 GetGDALDriverManager()->RegisterDriver( poDriver );
2692 }
2693