MongoError:拓扑已关闭,请连接

Posted

技术标签:

【中文标题】MongoError:拓扑已关闭,请连接【英文标题】:MongoError: Topology is closed, please connect 【发布时间】:2020-04-26 16:10:03 【问题描述】:

我是一名前端开发人员,试图在一个新的 Next 项目上扩展我的视野,第一次学习 Node、Mongo 和 GraphQL 的服务器端。 Apollo 让我印象深刻,因为我已经在之前的项目中使用过客户端 Apollo。

我一直在关注official docs,在那里我了解到apollo-datasource-mongodb(这似乎是将我的 Apollo 服务器直接插入本地 Mongo 数据库的最佳方式。不幸的是,似乎没有任何示例 repos包在行动中让我作弊,所以我只能得过且过。

我通过 mongod 在本地运行 mongo,我可以通过 mongo shell 成功执行 find() 查询,所以我知道数据库本身状况良好,包含近 600,000 条记录(我'正在处理一个相当大的数据集)。

我还可以访问位于 localhost:4000 的 Apollo Playground,因此我知道服务器正在正常启动并连接到数据库(我已经设法解决了相应的架构提示/错误)。

这是我在 Playground 中使用的查询:


  item(id: 22298006) 
    title
  

这是我的回复:


  "errors": [
    
      "message": "Topology is closed, please connect",
      "locations": [
        
          "line": 2,
          "column": 3
        
      ],
      "path": [
        "item"
      ],
      "extensions": 
        "code": "INTERNAL_SERVER_ERROR",
        "exception": 
          "name": "MongoError",
          "stacktrace": [
            "MongoError: Topology is closed, please connect",

            ...

          ]
        
      
    
  ],
  "data": 
    "item": null
  

我在下面附上了我的服务器文件。我怀疑这可能是某种超时错误,例如梳理所有 600k 记录以找到具有我提供的 ID 的记录需要很长时间?当我从 MongoClient 定义中删除 useUnifiedTopology: true 时,我得到一个不同的错误:

UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)

但我自己没有使用异步或承诺。我在想哪一个——我应该这样吗?我可以在等待findOneById() 的返回时以某种方式暂停该过程吗(如果这确实是问题所在)?

顺便说一句,我至少看到过一个示例代码库,其中 MongoClient 在其自身中包含了一个服务器声明(也来自'mongodb' npm 包)。实现类似的东西可以让我不必在每次我想处理我的项目时都用mongod 阻塞终端窗口吗?

非常感谢您抽出宝贵时间!如果我能完成这项工作,我肯定会在 Medium 上写一篇完整的文章,或者为其他希望将 MongoClient 与 ApolloServer 配对以获得快速简单的 API 的人铺平道路。

index.js

const  MongoClient  = require('mongodb');
const assert = require('assert');
const  ApolloServer, gql  = require('apollo-server');
const  MongoDataSource  = require('apollo-datasource-mongodb');


const client = new MongoClient('mongodb://localhost:27017/projectdb',  useNewUrlParser: true, useUnifiedTopology: true , (err) => 
  err && console.log(err);
);

client.connect((err) => 
  assert.equal(null, err);
  client.close();
);

const db = client.db();

class Items extends MongoDataSource 
  getItem(id) 
    return this.findOneById(id);
  


const typeDefs = gql`
  type Item 
    id: Int!
    title: String!
  
  type Query 
    item(id: Int!): Item
  
`;

const resolvers = 
  Query: 
    item: (_,  id ,  dataSources ) => dataSources.items.getItem(id),
  


const server = new ApolloServer(
  typeDefs,
  resolvers,
  dataSources: () => (
    items: new Items(db.collection('items')),
  ),
);

server.listen().then(( url ) => 
  console.log(`Server ready at $ url `);
);

【问题讨论】:

您需要在数据库操作后拥有此client.close();。去掉那里 嗨@srinivasy,感谢您的回复!不幸的是,将client.close(); 移动到const server = ... );server.listen()... 之间的空间仍然会导致与以前相同的错误。与将其移至文件的最后一行相同。 我还尝试了从const db = client.db(); 到文件末尾的所有内容并将其粘贴在assert.equal(null, err);client.close(); 之间,但没有运气——同样的错误。 这个return this.findOneById(id); 会返回什么以及id 是什么? client.connect() 中删除 client.close(); 后,你能做到吗 :: async getItem(id) let result = await this.findOneById(id); client.close(); return result; ,而且这一行 const client = new MongoClient() 不需要回调.. 【参考方案1】:

感谢 GitHub 在 apollo-datasource-mongodb 上的“使用者”下拉菜单,我能够欺骗其他一些存储库,这就是我最终得到的结果(在 cmets 中标记了更改):

const  MongoClient  = require('mongodb');
const assert = require('assert');
const  ApolloServer, gql  = require('apollo-server');
const  MongoDataSource  = require('apollo-datasource-mongodb');


// Isolated these for prominence and reuse
const dbURL = 'mongodb://localhost:27017';
const dbName = 'projectdb';

// Made each function async/await
// Swapped the datasource's findOneById() for the collection itself & standard Mongo functions
class Items extends MongoDataSource 
  async getItem(id) 
    return await this.collection.findOne(id: id);
  


const typeDefs = gql`
  type Item 
    id: Int!
    title: String!
  
  type Query 
    item(id: Int!): Item
  
`;

// Made each query async/await
const resolvers = 
  Query: 
    item: async (_,  id ,  dataSources ) => 
      return await dataSources.items.getItem(id);
    ,
  


// Move the ApolloServer constructor to its own function that takes the db
const init = (db) = 
  return new ApolloServer(
    typeDefs,
    resolvers,
    dataSources: () => (
      items: new Items(db.collection('items')),
    ),
  );


// Use .connect() instead of new MongoClient
// Pass the new db to the init function defined above once it's been defined
// Call server.listen() from within MongoClient
MongoClient.connect(dbURL,  useNewUrlParser: true, useUnifiedTopology: true , (err, client) => 
  assert.equal(null, err);
  const db = client.db(dbName);
  console.log(`Mongo database $ dbName  at $ dbURL `);

  const server = init(db);

  server.listen().then(( url ) => 
    console.log(`Server ready at $ url `);
  );
);

通过这些更改,位于 localhost:4000 的 Apollo Playground 运行良好!现在要解决我在查询时在客户端应用程序中遇到的 400 错误...

【讨论】:

你不必在getItem函数中等待,也不必声明它是异步的,只需返回promesse,调用getItem时等待【参考方案2】:

实际上还有一件事可能导致这种情况,因为我也遇到了同样的错误“拓扑已关闭,请连接”。

问题是,如果您有一个动态 IP 地址,那么在 MongoDB atlas 中您应该尝试允许所有 IP 地址。

添加IP地址:0.0.0.0/0 将这个允许所有的 IP 地址列入白名单后,我的所有问题都得到了解决。

动态IP图片0.0.0.0/0

【讨论】:

这不能解决我的问题。甚至在遇到此问题之前,我就已将“从任何地方”列入白名单。

以上是关于MongoError:拓扑已关闭,请连接的主要内容,如果未能解决你的问题,请参考以下文章

开玩笑单元测试返回“MongoError:拓扑被破坏”

MongoError:拓扑被破坏sailsjs

MongoError:拓扑被破坏sailsjs

MongoError:拓扑被破坏,NODEJS

MongoError:拓扑被破坏,NODEJS

MongoError:拓扑被破坏,我该如何修复它? [复制]