MongoError: Топология закрыта, пожалуйста, подключитесь - PullRequest
2 голосов
/ 09 января 2020

Я разработчик внешнего интерфейса, пытающийся расширить свой кругозор в новом проекте Next, изучая Node, Mon go и серверную часть GraphQL впервые. Apollo показался мне самым простым способом освоиться, поскольку я уже использовал клиентский Apollo в предыдущих проектах.

Я следовал официальным документам , где я узнал о apollo-datasource-mongodb (казалось бы, лучший способ подключить мой сервер Apollo прямо к локальной базе данных Mon go. К сожалению, для меня нет примеров репозиториев этого пакета в действии, чтобы я мог обмануть, так что меня оставили в тупике.

У меня mon go, работающий локально через mongod, и я могу выполнять успешные find() запросы через оболочку mon go, поэтому я знаю, что сама база данных находится в хорошем состоянии и содержит почти 600 000 записей (я работаю с довольно большим набором данных).

У меня также есть доступ к игровой площадке Apollo на localhost:4000, поэтому Я знаю, что сервер правильно запускается и подключается к базе данных (с соответствующими советами / ошибками схемы, которые мне с тех пор удалось устранить).

Вот запрос, который я использую на игровой площадке:

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

Я прикрепил файл моего сервера ниже. У меня есть подозрение, что это может быть какая-то ошибка тайм-аута, например, требуется много времени, чтобы прочесать все записи 600 КБ, чтобы найти ту, с указанным мной идентификатором? Когда я удаляю useUnifiedTopology: true из определения MongoClient, я получаю другую ошибку:

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)

, но я не использую asyn c или обещания сам. Что заставляет меня задуматься - я должен быть? Могу ли я как-то задержать процесс, пока я жду возврата из 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 }`);
});

Ответы [ 2 ]

1 голос
/ 10 января 2020

Благодаря выпадающему списку GitHub «Используется» на apollo-datasource-mongodb Мне удалось обмануть несколько других репозиториев, и вот что я закончил (с изменениями, отмеченными в комментариях):

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

С этими изменениями игровая площадка Apollo на localhost: 4000 прекрасно работает! Теперь, чтобы устранить ошибку 400, которую я получаю в своем клиентском приложении при запросе ...

0 голосов
/ 22 апреля 2020

На самом деле есть еще одна причина, которая может вызывать это, поскольку у меня также была точно такая же ошибка: «Топология закрыта, пожалуйста, подключитесь».

Дело в том, что если у вас есть динамический c IP-адрес, то в атласе MongoDB вы должны попытаться разрешить все IP-адреса.

Добавьте IP-адрес: 0.0.0.0/0 Все мои проблемы были решены после внесения в белый список этого IP-адреса, который разрешает все.

Изображение динамического c IP 0.0.0.0/0:

enter image description here

...