Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't Connect To MongoDB Atlas Cluster #3347

Closed
pointtoken opened this issue Jan 1, 2019 · 20 comments · Fixed by #7136, mattwelke/typeorm-postgres-example#165 or newerton/gobarber-2-backend#17
Labels

Comments

@pointtoken
Copy link

Issue type:

[ ] question
[X] bug report
[ ] feature request
[ ] documentation issue

Database system/driver:

[ ] cordova
[X] mongodb
[ ] mssql
[ ] mysql / mariadb
[ ] oracle
[ ] postgres
[ ] sqlite
[ ] sqljs
[ ] react-native
[ ] expo

TypeORM version:

[X] latest
[ ] @next
[ ] 0.x.x (or put your version here)

Steps to reproduce or a small repository showing the problem:

I have a valid connection string to a Mongo Atlas DB that I am trying to use with TypeORM. I know the connection string works because I have used it from Python and from the Mongo shell. But it doesn't work from typeorm. I have tried both the mongodb:// and mongo+srv synax. Not sure how to debug or figure this one out. Here is the error:

(node:19257) DeprecationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.
{ MongoNetworkError: connection 5 to cluster0-XXXX.mongodb.net:27017 closed
    at Socket.<anonymous> (/home/administrator/Source/Repos/emoon-relayer/node_modules/mongodb-core/lib/connection/connection.js:276:9)
    at Object.onceWrapper (events.js:273:13)
    at Socket.emit (events.js:182:13)
    at TCP._handle.close (net.js:611:12)
  name: 'MongoNetworkError',
  errorLabels: [ 'TransientTransactionError' ],
  [Symbol(mongoErrorContextSymbol)]: {} }
@vlapo
Copy link
Contributor

vlapo commented Jan 2, 2019

Did you try add useNewUrlParser: true to your connection config?

@rustamwin
Copy link
Contributor

rustamwin commented Jan 3, 2019

Try add dbName: <your database name> to your connection options
https://stackoverflow.com/questions/48917591/fail-to-connect-mongoose-to-atlas/48917626#48917626

@pointtoken
Copy link
Author

pointtoken commented Jan 3, 2019

Thanks guys -- yes, I added useNewUrlParser. Oddly, it still gives a warning even though it gets passed. Also, the dbName is unnecessary since the database name gets passed in as part of the URL connection string.

I believe there is something awry with how the Mongo Driver works with typeOrm. At first blush, looking at the code in the Mongo Driver, I see how all these nullable options get set, which could be problematic. It would be nice to construct the options object with only the values passed.

@vlapo
Copy link
Contributor

vlapo commented Jan 4, 2019

After few tries I have two valid configurations for typeorm and mongo atlas:

const connection = await createConnection({
            type: "mongodb",
            useNewUrlParser: true,
            url: "mongodb://admin:password@testcluster0-shard-00-00-1cmyo.mongodb.net:27017,testcluster0-shard-00-01-1cmyo.mongodb.net:27017,testcluster0-shard-00-02-1cmyo.mongodb.net:27017/test?ssl=true&replicaSet=TestCluster0-shard-0&authSource=admin&retryWrites=true",
            ssl: true,
            authSource: "admin",
            replicaSet: "TestCluster0-shard-0"
        });

and second one

const connection = await createConnection({
            type: "mongodb",
            url: "mongodb+srv://admin:admin@testcluster0-1cmyo.mongodb.net/test?retryWrites=true",
            ssl: true,
            authSource: "admin",
            replicaSet: "TestCluster0-shard-0"
        });

But I think @pointtoken is right. Calling mongodb connect method with undefined option properties overwrites settings from url.

@pointtoken
Copy link
Author

@vlapo nice that worked!

@vlapo
Copy link
Contributor

vlapo commented Jan 4, 2019

Still I think we should not pass all mongo options to mongo client with undefined values. Our current implementation will overwrite all options from url with undefined.

@vincedgy
Copy link

vincedgy commented Nov 3, 2019

I know it's a closed case...
but since I'm using dotenv and MongoDB Atlas this is what I found :

.env

TYPEORM_CONNECTION = mongodb
TYPEORM_URL = mongodb+srv://admin:password@cluster-XXXXX-pSDig.mongodb.net/graphql-ts?retryWrites=true&w=majority
TYPEORM_DATABASE = graphql-ts

TYPEORM_ENTITIES = src/entity/*.ts
TYPEORM_MIGRATIONS = src/migration/**/*.ts
TYPEORM_ENTITIES_DIR = src/entity
TYPEORM_SUBSCRIBERS_DIR = src/subscriber
TYPEORM_MIGRATIONS_DIR = src/migration

TYPEORM_DRIVER_EXTRA = '{"useUnifiedTopology":true}'

@oliviermattei
Copy link

oliviermattei commented Feb 5, 2020

Hello,

I have the same problem with a free Mongo Atlas cluster.

type: 'mongodb',
      url:
        'mongodb+srv://***:***@test-tqajp.gcp.mongodb.net/test?retryWrites=true&w=majority',
      entities: [join(__dirname, '**', '*.type.{ts,js}')],
      synchronize: true,
      useNewUrlParser: false,
      logging: true,

[TypeOrmModule] Unable to connect to the database. Retrying (1)... +2006ms

I'm using nestjs, but with mongoose all works fine. But i'd like using typeorm because i need multiple connections with other kind of databases. I don't think it's a problem of @nestjs/typeorm package.

@Philip-Nunoo
Copy link

@oliviermattei facing the same issue did you find a solution to this.

@Adondriel
Copy link

Adondriel commented Jul 17, 2020

Updating this ticket with a code block that got mine to work, using the free cluster.

  const connection = await createConnection({
    type: 'mongodb',
    url: 'mongodb+srv://<user>:<pass>@test-cluster.cgl5c.mongodb.net/<db name>',
    w: 'majority',
    ssl: true,
    authSource: 'admin',
    entities: ['dist/**/*.entity.js'],
  });

nocheintobi added a commit to nocheintobi/typeorm that referenced this issue Dec 2, 2020
As described in [MongoDB Docs](https://docs.mongodb.com/manual/reference/connection-string/#dns-seed-list-connection-format), an additional connection string format called DNS Seed List Connection format can be used. As this is the default format for MongoDB Atlas, the hosted service of MongoDB, this should be available also for typeorm. 
The connection format is identified by the url-schema "mongodb+srv" and does not allow specifying a port.
Fixes typeorm#3347
Fixes typeorm#3133
@Funnelll
Copy link

Funnelll commented Dec 7, 2020

I had the same issue. Passing the MongoDB Atlas as URL (mongodb://) lead to the
MongoNetworkError: connection X to cluster0-XXXX.mongodb.net:27017 closed error. Passing the host, port, username, password, database, authSource, and ssl worked. After looking more into it, it seems that only one host is picked up (and it seems to me the parameters are ignored as well) from the URL.

Since I didn't want to change my environment variable in my environment, I fixed this by creating a method that parses the URL and constructs the options correctly. Here are the details of the implementation in case it becomes handy for anybody else.

private static async connectToDataBase() {

        const options = {
            useNewUrlParser: true,
            bufferMaxEntries: 0,
            connectTimeoutMS: 60000,
            useUnifiedTopology: true,
            serverSelectionTimeoutMS: 60000
        };

        const connectionOptions:any = await getConnectionOptions();
        Object.assign(connectionOptions, options);
        Object.assign(connectionOptions, Server.extractDriverOptions(Environment.databaseUrl));

        try{
            await createConnection();
            logger.info(`Connected to database ${connectionOptions.host}`, Server);
        } catch (error) {
            logger.error(`Failed to connect to database ${connectionOptions.host}: ${error}: ${error.stack}`, Server);
        }
}
private static extractDriverOptions (url) {
        const type = url.split(":")[0];
        const firstSlashes = url.indexOf("//");
        const preBase = url.substr(firstSlashes + 2);
        const secondSlash = preBase.indexOf("/");
        const base = (secondSlash !== -1) ? preBase.substr(0, secondSlash) : preBase;
        let afterBase = (secondSlash !== -1) ? preBase.substr(secondSlash + 1) : undefined;
        // remove mongodb query params
        if (afterBase && afterBase.indexOf("?") !== -1) {
            afterBase = afterBase.substr(0, afterBase.indexOf("?"));
        }
        const lastAtSign = base.lastIndexOf("@");
        const usernameAndPassword = base.substr(0, lastAtSign);
        const hostAndPort = base.substr(lastAtSign + 1);
        let username = usernameAndPassword;
        let password = "";
        const firstColon = usernameAndPassword.indexOf(":");
        if (firstColon !== -1) {
            username = usernameAndPassword.substr(0, firstColon);
            password = usernameAndPassword.substr(firstColon + 1);
        }
        const hostAndPortParts = hostAndPort.split(',');
        let part;
        let host;
        let port;
        for (let i=0; i<hostAndPortParts.length; i++) {
            if (i === 0) {
                part = hostAndPortParts[i].split(":");
                host = part[0];
                port= part[1];
            } else {
                host = host + "," + hostAndPortParts[i].split(":")[0];
            }
        }

        const driverOptions = {
            type: type,
            host: host,
            username: decodeURIComponent(username),
            password: decodeURIComponent(password),
            port: port ? parseInt(port) : undefined,
            database: afterBase || undefined
        };
        const properties = url.split('?')[1]?.split('&');
        let property;
        let value: string;
        for (let i=0; i<properties.length; i++) {
            property = properties[i].split('=')[0];
            value = properties[i].split('=')[1];
            if (value.toLowerCase().indexOf('true') > -1 || value.toLowerCase().indexOf('false') > -1) {
                driverOptions[property] = (value.toLowerCase().indexOf('true') > -1);
            } else {
                driverOptions[property] = value;
            }
        }

        return driverOptions;
 }

Here is what my ormconfig.json looks like:

{
  "type": "mongodb",
  "synchronize": false,
  "logging": false,
  "entities": [
    "build/entities/**/*.js"
  ],
  "cli": {
     "entitiesDir": "src/entity"
  }
}

I am using "mongodb": "^3.6.3", "typeorm": "^0.2.29".

P.S. Please note that this implementation doesn't account for cases where the configuration has a parameter with a number value (but it is an easy fix to add if you are sending a parameter that has a numeric value in the URL).

@PierBusDev
Copy link

PierBusDev commented Dec 11, 2020

I am still getting this problem with typeorm 0.2.29.
None of the solutions posted above work right now

EDIT: I found a working but undocumentend solution, if you use one of your cluster shard addresses instead of the general address mongo atlas gives you, the connection works

So instead of
mongodb+srv://<user>:<password>@cluster0.somethingsomething.mongodb.net/<dbname>
use something like (you'll find three valid for your conf in your mongoatlas page):
mongodb+srv://<user>:<password>@cluster0-shard-00-00.somethingsomething.mongodb.net/<dbname>

hope it helps

@aleccool213
Copy link
Contributor

@PierBusDev is correct. MongoDB Atlas support is currently broken unless you specify the exact shard you want to connect to. Wasted a few hours on this :/ This issue should be re-opened with a fix or with some documentation.

pleerock pushed a commit that referenced this issue Dec 22, 2020
As described in [MongoDB Docs](https://docs.mongodb.com/manual/reference/connection-string/#dns-seed-list-connection-format), an additional connection string format called DNS Seed List Connection format can be used. As this is the default format for MongoDB Atlas, the hosted service of MongoDB, this should be available also for typeorm. 
The connection format is identified by the url-schema "mongodb+srv" and does not allow specifying a port.
Fixes #3347
Fixes #3133
@smasala
Copy link

smasala commented Jan 3, 2021

Can confirm - using the shard worked when using nestjs, typeorm and mongodb atlas 🤦

@smasala
Copy link

smasala commented Jan 16, 2021

v0.2.30 fixes the issue. Can connect to an atlas cluster again. Thanks @pleerock!

@jrista
Copy link

jrista commented Feb 3, 2021

Hmm. So, we seem to be in a catch-22. I upgraded to 0.2.30, but did not change my mongo connection string, which I REVERTED to a mongo:// from mongo+srv:// after upgrading to 0.2.29 before and having problems connecting to mongo. So my connection currently uses a STANDARD mongo connection string...

After upgrading to 0.2.30 a short while ago, our connection to mongo stopped working. It just would time out trying to connect. We updated numerous modules at once, and it took a bit of experimentation to figure out that it is the 0.2.30 version of TypeORM that is causing the problem.

So while we may have gained the ability to use mongo+srv:// type connection strings, we seem to have LOST the ability to use mongo:// type connection strings...

I would offer it is best if we can use both types of connection strings, as necessary, to connect TypeORM to various mongo databases.

@AmbassEugene
Copy link

So the below worked for me. I am using Nestjs

{
  "type": "mongodb",
  "url": "mongodb+srv://<user>:<password>@cluster0.somethingsomething.mongodb.net/<dbname>?retryWrites=true&w=majority",
  "useNewUrlParser": true,
  "synchronize": true,
  "logging": true,
  "useUnifiedTopology": true,
  "entities": ["dist/**/*.entity{.ts,.js}"]
}

@Drakoun
Copy link

Drakoun commented Apr 26, 2021

Thank you @AmbassEugene, it worked for me.

@bernardorz
Copy link

Thank you @AmbassEugene , it worked with your setup.

@cryptiklemur
Copy link
Contributor

cryptiklemur commented Apr 6, 2023

This doesn't seem to work anymore?

edit: Looks like mongodb@5 breaks this. Downgrading to 4.15 fixes it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment