@@ -437,13 +437,11 @@ MongoDB.prototype.connect = function(callback) {
437
437
if ( callback ) callback ( err ) ;
438
438
}
439
439
440
- const urlObj = new URL ( self . settings . url ) ;
441
-
442
- if ( ( urlObj . pathname === '' ||
443
- urlObj . pathname . split ( '/' ) [ 1 ] === '' ) &&
444
- typeof self . settings . database === 'string' ) {
445
- urlObj . pathname = self . settings . database ;
446
- self . settings . url = urlObj . toString ( ) ;
440
+ // This is special processing if database is not part of url, but is in settings
441
+ if ( self . settings . url && self . settings . database ) {
442
+ if ( self . settings . url . indexOf ( '/' + self . settings . database ) === - 1 ) {
443
+ self . settings . url = processMongoDBURL ( self . settings . database , self . settings . url ) ;
444
+ }
447
445
}
448
446
449
447
const mongoClient = new mongodb . MongoClient ( self . settings . url , validOptions ) ;
@@ -2586,3 +2584,101 @@ function buildOptions(requiredOptions, connectorOptions) {
2586
2584
return Object . assign ( { } , connectorOptions , requiredOptions ) ;
2587
2585
}
2588
2586
}
2587
+
2588
+ /**
2589
+ * This method parses a Mongo connection url string and refers the formats
2590
+ * specified at: https://www.mongodb.com/docs/manual/reference/connection-string/.
2591
+ * Since there are cases where database is not specified in the url, but as a settings property,
2592
+ * the code has to reflect that in the url otherwise the MongoDB driver defaults to 'admin' db.
2593
+ * @param {string } settingsDatabase - the database that will be added if url doesn't have a db specified
2594
+ * @param {string } mongoUrl - the url to be processed for database manipulation
2595
+ */
2596
+ function processMongoDBURL ( settingsDatabase , mongoUrl ) {
2597
+ // Reference: https://www.mongodb.com/docs/manual/reference/connection-string/
2598
+ // Standard format::: mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]
2599
+ // DNS SeedList format::: mongodb+srv://server.example.com/?connectTimeoutMS=300000&authSource=aDifferentAuthDB
2600
+ // Actual replicaset example::: mongodb://mongodb1.example.com:27317,mongodb2.example.com:27017/?connectTimeoutMS=300000&replicaSet=mySet&authSource=aDifferentAuthDB
2601
+
2602
+ if ( mongoUrl ) {
2603
+ // 1. Know protocol
2604
+ let baseUrl = '' ;
2605
+ if ( mongoUrl . startsWith ( 'mongodb:' ) )
2606
+ baseUrl = 'mongodb://' ;
2607
+ else if ( mongoUrl . startsWith ( 'mongodb+srv:' ) )
2608
+ baseUrl = 'mongodb+srv://' ;
2609
+ else if ( mongoUrl . startsWith ( 'loopback-connector-mongodb:' ) )
2610
+ baseUrl = 'loopback-connector-mongodb://' ;
2611
+ else if ( mongoUrl . startsWith ( 'loopback-connector-mongodb+srv:' ) )
2612
+ baseUrl = 'loopback-connector-mongodb+srv://' ;
2613
+ else
2614
+ return mongoUrl ; // Not a MongoURL that we can process
2615
+
2616
+ let remainderUrl = mongoUrl . substring ( baseUrl . length ) ;
2617
+ // 2. Check if userId/password is present
2618
+ let uidPassword = '' ;
2619
+ if ( remainderUrl . indexOf ( '@' ) !== - 1 ) {
2620
+ const parts = remainderUrl . split ( '@' ) ;
2621
+ uidPassword = parts [ 0 ] ;
2622
+ if ( parts . length === 2 )
2623
+ remainderUrl = parts [ 1 ] ;
2624
+ else
2625
+ remainderUrl = '' ;
2626
+ }
2627
+ let hosts = '' ;
2628
+ let dbName = '' ;
2629
+ let options = '' ;
2630
+ let hostsArray = [ ] ;
2631
+ // 3. Check if comma separated replicas are specified
2632
+ if ( remainderUrl . indexOf ( ',' ) !== - 1 ) {
2633
+ hostsArray = remainderUrl . split ( ',' ) ;
2634
+ remainderUrl = hostsArray [ hostsArray . length - 1 ] ;
2635
+ }
2636
+
2637
+ // 4. Check if authDB is specified in the URL
2638
+ const slashIndex = remainderUrl . indexOf ( '/' ) ;
2639
+ if ( ( slashIndex !== - 1 ) ) {
2640
+ if ( slashIndex !== ( remainderUrl . length - 1 ) ) {
2641
+ const optionsIndex = remainderUrl . indexOf ( '?' ) ;
2642
+ if ( optionsIndex !== - 1 ) {
2643
+ options = remainderUrl . substring ( optionsIndex + 1 ) ;
2644
+ dbName = remainderUrl . substring ( slashIndex + 1 , optionsIndex ) ;
2645
+ } else {
2646
+ // No DB options specified
2647
+ dbName = remainderUrl . substring ( slashIndex + 1 ) ;
2648
+ }
2649
+ }
2650
+
2651
+ if ( hostsArray . length > 1 ) {
2652
+ const newHosts = hostsArray ;
2653
+ newHosts . pop ( ) ;
2654
+ newHosts . push ( remainderUrl . substring ( 0 , slashIndex ) ) ;
2655
+ hosts = newHosts . join ( ',' ) ;
2656
+ } else {
2657
+ hosts = remainderUrl . substring ( 0 , slashIndex ) ;
2658
+ }
2659
+ } else {
2660
+ // No database specified
2661
+ if ( hostsArray . length > 1 )
2662
+ hosts = hostsArray . join ( ',' ) ;
2663
+ else
2664
+ hosts = remainderUrl ;
2665
+ }
2666
+
2667
+ // 5. Reconstruct url, but this time add database from settings if URL didn't have it
2668
+ // The below code has an overlap with generateMongoDBURL()
2669
+ let modifiedUrl = baseUrl ;
2670
+
2671
+ if ( uidPassword )
2672
+ modifiedUrl += uidPassword + '@' ;
2673
+ if ( hosts )
2674
+ modifiedUrl += hosts ;
2675
+
2676
+ modifiedUrl += '/' + ( dbName ? dbName : settingsDatabase ) ;
2677
+
2678
+ if ( options )
2679
+ modifiedUrl += '?' + options ;
2680
+
2681
+ return modifiedUrl ;
2682
+ }
2683
+ return mongoUrl ;
2684
+ }
0 commit comments