MongoError:拓扑已关闭,请连接 [英] MongoError: Topology is closed, please connect

查看:619
本文介绍了MongoError:拓扑已关闭,请连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一名前端开发人员,试图在新的Next项目上拓展视野,第一次学习Node,Mongo和GraphQL的服务器端. Apollo吸引了我,因为我已经在以前的项目中使用过客户端Apollo.

我一直在关注官方文档,在这里我了解了 apollo-datasource-mongodb (似乎是插入我的Apollo的最佳方法服务器直接进入本地的Mongo数据库.不幸的是,似乎没有这个软件包的示例存储库可供我欺骗,因此我不得不去摸索.

我有通过mongod在本地运行的mongo,并且可以通过mongo shell成功执行find()查询,因此我知道数据库本身状态良好,并且包含近 600,000条记录(我正在使用相当大的数据集).

我还可以访问localhost:4000处的Apollo游乐场,因此我知道服务器正在正常启动并连接到数据库(具有自此以来一直设法解决的适当的架构提示/错误).

这是我在操场上使用的查询:

{
  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本身包含了一个Server声明(也来自'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 }`);
});

解决方案

感谢GitHub在official docs, where I learned of apollo-datasource-mongodb (seemingly the best way to plug my Apollo Server straight into a local Mongo database. Unfortunately there don't seem to be any example repos of this package in action for me to cheat off of so I've been left to muddle through.

I have mongo running locally via mongod and I can perform successful find() queries through the mongo shell, so I know the database itself is in good shape and contains nearly 600,000 records (I'm working with a rather large dataset).

I also have access to the Apollo Playground at localhost:4000 so I know the server is starting properly and connecting to the database (with appropriate Schema tips/errors I've since managed to resolve).

Here's the query I'm using in the Playground:

{
  item(id: 22298006) {
    title
  }
}

and here's what I'm getting back in response:

{
  "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
  }
}

I've attached my server file below. I have a suspicion that this might be some kind of timeout error, like it takes to long to comb through all 600k records to find the one with the ID I provided? When I remove useUnifiedTopology: true from the MongoClient definition I get a different error:

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)

but I'm not using async or promises myself. Which has me thinking — should I be? Could I somehow hold up the process while I wait for the return from findOneById() (if that is, indeed, the problem)?

As an aside, I've seen at least one example codebase where MongoClient included within itself a Server declaration (also from the 'mongodb' npm package). Would implementing something like that save me from having to block up a terminal window with mongod every time I want to work on my project?

Thank you so much for your time! If I can get this working I'll definitely do a full writeup on Medium or something to pave the way for others looking to pair MongoClient with ApolloServer for a quick and easy 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 }`);
});

解决方案

Thanks to GitHub's "Used By" dropdown on the apollo-datasource-mongodb I was able to cheat off a few other repositories, and here's what I ended up with (with changes marked in comments):

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 }`);
  });
});

With these changes, the Apollo Playground at localhost:4000 works great! Now to solve the 400 error I'm getting in my client app when I query...

这篇关于MongoError:拓扑已关闭,请连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆